feat: 实现 IoT 卡轮询系统(支持千万级卡规模)
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m35s

实现功能:
- 实名状态检查轮询(可配置间隔)
- 卡流量检查轮询(支持跨月流量追踪)
- 套餐检查与超额自动停机
- 分布式并发控制(Redis 信号量)
- 手动触发轮询(单卡/批量/条件筛选)
- 数据清理配置与执行
- 告警规则与历史记录
- 实时监控统计(队列/性能/并发)

性能优化:
- Redis 缓存卡信息,减少 DB 查询
- Pipeline 批量写入 Redis
- 异步流量记录写入
- 渐进式初始化(10万卡/批)

压测工具(scripts/benchmark/):
- Mock Gateway 模拟上游服务
- 测试卡生成器
- 配置初始化脚本
- 实时监控脚本

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-05 17:32:44 +08:00
parent b11edde720
commit 931e140e8e
104 changed files with 16883 additions and 87 deletions

View File

@@ -38,9 +38,15 @@ type StandaloneIotCardResponse struct {
ActivatedAt *time.Time `json:"activated_at,omitempty" description:"激活时间"`
ActivationStatus int `json:"activation_status" description:"激活状态 (0:未激活, 1:已激活)"`
RealNameStatus int `json:"real_name_status" description:"实名状态 (0:未实名, 1:已实名)"`
NetworkStatus int `json:"network_status" description:"网络状态 (0:停机, 1:开机)"`
DataUsageMB int64 `json:"data_usage_mb" description:"累计流量使用(MB)"`
SeriesID *uint `json:"series_id,omitempty" description:"套餐系列ID"`
NetworkStatus int `json:"network_status" description:"网络状态 (0:停机, 1:开机)"`
DataUsageMB int64 `json:"data_usage_mb" description:"累计流量使用(MB)"`
CurrentMonthUsageMB float64 `json:"current_month_usage_mb" description:"本月已用流量(MB)"`
CurrentMonthStartDate *time.Time `json:"current_month_start_date,omitempty" description:"本月开始日期"`
LastMonthTotalMB float64 `json:"last_month_total_mb" description:"上月流量总量(MB)"`
LastDataCheckAt *time.Time `json:"last_data_check_at,omitempty" description:"最后流量检查时间"`
LastRealNameCheckAt *time.Time `json:"last_real_name_check_at,omitempty" description:"最后实名检查时间"`
EnablePolling bool `json:"enable_polling" description:"是否参与轮询"`
SeriesID *uint `json:"series_id,omitempty" description:"套餐系列ID"`
SeriesName string `json:"series_name,omitempty" description:"套餐系列名称"`
FirstCommissionPaid bool `json:"first_commission_paid" description:"一次性佣金是否已发放"`
AccumulatedRecharge int64 `json:"accumulated_recharge" description:"累计充值金额(分)"`

View File

@@ -0,0 +1,84 @@
package dto
import "time"
// CreatePollingAlertRuleReq 创建告警规则请求
type CreatePollingAlertRuleReq struct {
RuleName string `json:"rule_name" validate:"required,max=100" description:"规则名称"`
TaskType string `json:"task_type" validate:"required" description:"任务类型 (polling:realname/polling:carddata/polling:package)"`
MetricType string `json:"metric_type" validate:"required" description:"指标类型 (queue_size/success_rate/avg_duration/concurrency)"`
Operator string `json:"operator" validate:"omitempty,oneof=> >= < <= ==" description:"比较运算符,默认 >"`
Threshold float64 `json:"threshold" validate:"required" description:"阈值"`
AlertLevel string `json:"alert_level" validate:"required,oneof=warning critical" description:"告警级别 (warning/critical)"`
CooldownMinutes int `json:"cooldown_minutes" validate:"omitempty,min=0,max=1440" description:"冷却时间(分钟)默认5分钟"`
NotifyChannels string `json:"notify_channels" validate:"omitempty" description:"通知渠道(JSON格式)"`
}
// UpdatePollingAlertRuleReq 更新告警规则请求Body 部分)
type UpdatePollingAlertRuleReq struct {
RuleName *string `json:"rule_name" validate:"omitempty,max=100" description:"规则名称"`
Threshold *float64 `json:"threshold" validate:"omitempty" description:"阈值"`
AlertLevel *string `json:"alert_level" validate:"omitempty,oneof=warning critical" description:"告警级别"`
Status *int `json:"status" validate:"omitempty,oneof=0 1" description:"状态 (0:禁用, 1:启用)"`
CooldownMinutes *int `json:"cooldown_minutes" validate:"omitempty,min=0,max=1440" description:"冷却时间(分钟)"`
NotifyChannels *string `json:"notify_channels" validate:"omitempty" description:"通知渠道"`
}
// UpdatePollingAlertRuleParams 更新告警规则参数(包含路径参数和 Body
type UpdatePollingAlertRuleParams struct {
IDReq
UpdatePollingAlertRuleReq
}
// PollingAlertRuleResp 告警规则响应
type PollingAlertRuleResp struct {
ID uint `json:"id" description:"规则ID"`
RuleName string `json:"rule_name" description:"规则名称"`
TaskType string `json:"task_type" description:"任务类型"`
TaskTypeName string `json:"task_type_name" description:"任务类型名称"`
MetricType string `json:"metric_type" description:"指标类型"`
MetricTypeName string `json:"metric_type_name" description:"指标类型名称"`
Operator string `json:"operator" description:"比较运算符"`
Threshold float64 `json:"threshold" description:"阈值"`
AlertLevel string `json:"alert_level" description:"告警级别"`
Status int `json:"status" description:"状态 (0:禁用, 1:启用)"`
CooldownMinutes int `json:"cooldown_minutes" description:"冷却时间(分钟)"`
NotifyChannels string `json:"notify_channels" description:"通知渠道"`
CreatedAt time.Time `json:"created_at" description:"创建时间"`
UpdatedAt time.Time `json:"updated_at" description:"更新时间"`
}
// PollingAlertRuleListResp 告警规则列表响应
type PollingAlertRuleListResp struct {
Items []*PollingAlertRuleResp `json:"items" description:"告警规则列表"`
}
// PollingAlertHistoryResp 告警历史响应
type PollingAlertHistoryResp struct {
ID uint `json:"id" description:"历史ID"`
RuleID uint `json:"rule_id" description:"规则ID"`
RuleName string `json:"rule_name" description:"规则名称"`
TaskType string `json:"task_type" description:"任务类型"`
MetricType string `json:"metric_type" description:"指标类型"`
AlertLevel string `json:"alert_level" description:"告警级别"`
Threshold float64 `json:"threshold" description:"阈值"`
CurrentValue float64 `json:"current_value" description:"触发时的值"`
Message string `json:"message" description:"告警消息"`
CreatedAt time.Time `json:"created_at" description:"触发时间"`
}
// PollingAlertHistoryListResp 告警历史列表响应
type PollingAlertHistoryListResp struct {
Items []*PollingAlertHistoryResp `json:"items" description:"告警历史列表"`
Total int64 `json:"total" description:"总数"`
Page int `json:"page" description:"当前页"`
PageSize int `json:"page_size" description:"每页数量"`
TotalPages int `json:"total_pages" description:"总页数"`
}
// ListPollingAlertHistoryReq 查询告警历史请求
type ListPollingAlertHistoryReq struct {
RuleID *uint `json:"rule_id" query:"rule_id" description:"规则ID"`
Page int `json:"page" query:"page" validate:"omitempty,min=1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" description:"每页数量"`
}

View File

@@ -0,0 +1,103 @@
package dto
import "time"
// CreateDataCleanupConfigReq 创建数据清理配置请求
type CreateDataCleanupConfigReq struct {
TargetTable string `json:"table_name" validate:"required,max=100" description:"表名"`
RetentionDays int `json:"retention_days" validate:"required,min=7" description:"保留天数最少7天"`
BatchSize int `json:"batch_size" validate:"omitempty,min=1000,max=100000" description:"每批删除条数默认10000"`
Description string `json:"description" validate:"omitempty,max=500" description:"配置说明"`
}
// UpdateDataCleanupConfigReq 更新数据清理配置请求Body 部分)
type UpdateDataCleanupConfigReq struct {
RetentionDays *int `json:"retention_days" validate:"omitempty,min=7" description:"保留天数"`
BatchSize *int `json:"batch_size" validate:"omitempty,min=1000,max=100000" description:"每批删除条数"`
Enabled *int `json:"enabled" validate:"omitempty,oneof=0 1" description:"是否启用0-禁用1-启用"`
Description *string `json:"description" validate:"omitempty,max=500" description:"配置说明"`
}
// UpdateDataCleanupConfigParams 更新数据清理配置参数(包含路径参数和 Body
type UpdateDataCleanupConfigParams struct {
IDReq
UpdateDataCleanupConfigReq
}
// DataCleanupConfigResp 数据清理配置响应
type DataCleanupConfigResp struct {
ID uint `json:"id" description:"配置ID"`
TargetTable string `json:"table_name" description:"表名"`
RetentionDays int `json:"retention_days" description:"保留天数"`
BatchSize int `json:"batch_size" description:"每批删除条数"`
Enabled int `json:"enabled" description:"是否启用0-禁用1-启用"`
Description string `json:"description" description:"配置说明"`
CreatedAt time.Time `json:"created_at" description:"创建时间"`
UpdatedAt time.Time `json:"updated_at" description:"更新时间"`
UpdatedBy *uint `json:"updated_by,omitempty" description:"更新人ID"`
}
// DataCleanupConfigListResp 数据清理配置列表响应
type DataCleanupConfigListResp struct {
Items []*DataCleanupConfigResp `json:"items" description:"配置列表"`
}
// DataCleanupLogResp 数据清理日志响应
type DataCleanupLogResp struct {
ID uint `json:"id" description:"日志ID"`
TargetTable string `json:"table_name" description:"表名"`
CleanupType string `json:"cleanup_type" description:"清理类型scheduled/manual"`
RetentionDays int `json:"retention_days" description:"保留天数"`
DeletedCount int64 `json:"deleted_count" description:"删除记录数"`
DurationMs int64 `json:"duration_ms" description:"执行耗时(毫秒)"`
Status string `json:"status" description:"状态success/failed/running"`
ErrorMessage string `json:"error_message,omitempty" description:"错误信息"`
StartedAt time.Time `json:"started_at" description:"开始时间"`
CompletedAt *time.Time `json:"completed_at,omitempty" description:"完成时间"`
TriggeredBy *uint `json:"triggered_by,omitempty" description:"触发人ID"`
}
// DataCleanupLogListResp 数据清理日志列表响应
type DataCleanupLogListResp struct {
Items []*DataCleanupLogResp `json:"items" description:"日志列表"`
Total int64 `json:"total" description:"总数"`
Page int `json:"page" description:"当前页"`
PageSize int `json:"page_size" description:"每页数量"`
TotalPages int `json:"total_pages" description:"总页数"`
}
// ListDataCleanupLogReq 查询数据清理日志请求
type ListDataCleanupLogReq struct {
TableName string `json:"table_name" query:"table_name" description:"表名筛选"`
Page int `json:"page" query:"page" validate:"omitempty,min=1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" description:"每页数量"`
}
// DataCleanupPreviewResp 数据清理预览响应
type DataCleanupPreviewResp struct {
Items []*DataCleanupPreviewItem `json:"items" description:"预览列表"`
}
// DataCleanupPreviewItem 数据清理预览项
type DataCleanupPreviewItem struct {
TableName string `json:"table_name" description:"表名"`
RetentionDays int `json:"retention_days" description:"保留天数"`
RecordCount int64 `json:"record_count" description:"待清理记录数"`
Description string `json:"description" description:"配置说明"`
}
// DataCleanupProgressResp 数据清理进度响应
type DataCleanupProgressResp struct {
IsRunning bool `json:"is_running" description:"是否正在运行"`
CurrentTable string `json:"current_table,omitempty" description:"当前清理的表"`
TotalTables int `json:"total_tables" description:"总表数"`
ProcessedTables int `json:"processed_tables" description:"已处理表数"`
TotalDeleted int64 `json:"total_deleted" description:"已删除记录数"`
StartedAt *time.Time `json:"started_at,omitempty" description:"开始时间"`
LastLog *DataCleanupLogResp `json:"last_log,omitempty" description:"最近一条清理日志"`
}
// TriggerDataCleanupReq 手动触发数据清理请求
type TriggerDataCleanupReq struct {
TableName string `json:"table_name" validate:"omitempty,max=100" description:"表名,为空则清理所有"`
}

View File

@@ -0,0 +1,32 @@
package dto
// GetPollingConcurrencyReq 获取指定任务类型的并发配置请求
type GetPollingConcurrencyReq struct {
TaskType string `path:"task_type" description:"任务类型" required:"true"`
}
// UpdatePollingConcurrencyReq 更新轮询并发配置请求
type UpdatePollingConcurrencyReq struct {
TaskType string `path:"task_type" description:"任务类型" required:"true"`
MaxConcurrency int `json:"max_concurrency" validate:"required,min=1,max=1000" description:"最大并发数1-1000"`
}
// PollingConcurrencyResp 轮询并发配置响应
type PollingConcurrencyResp struct {
TaskType string `json:"task_type" description:"任务类型"`
TaskTypeName string `json:"task_type_name" description:"任务类型名称"`
MaxConcurrency int `json:"max_concurrency" description:"最大并发数"`
Current int64 `json:"current" description:"当前并发数"`
Available int64 `json:"available" description:"可用并发数"`
Utilization float64 `json:"utilization" description:"使用率(百分比)"`
}
// PollingConcurrencyListResp 轮询并发配置列表响应
type PollingConcurrencyListResp struct {
Items []*PollingConcurrencyResp `json:"items" description:"并发配置列表"`
}
// ResetPollingConcurrencyReq 重置轮询并发计数请求
type ResetPollingConcurrencyReq struct {
TaskType string `json:"task_type" validate:"required" description:"任务类型"`
}

View File

@@ -0,0 +1,81 @@
package dto
// CreatePollingConfigRequest 创建轮询配置请求
type CreatePollingConfigRequest struct {
ConfigName string `json:"config_name" validate:"required,min=1,max=100" required:"true" minLength:"1" maxLength:"100" description:"配置名称"`
CardCondition string `json:"card_condition" validate:"omitempty,oneof=not_real_name real_name activated suspended" description:"卡状态条件 (not_real_name:未实名, real_name:已实名, activated:已激活, suspended:已停用)"`
CardCategory string `json:"card_category" validate:"omitempty,oneof=normal industry" description:"卡业务类型 (normal:普通卡, industry:行业卡)"`
CarrierID *uint `json:"carrier_id" validate:"omitempty" description:"运营商ID可选精确匹配"`
Priority int `json:"priority" validate:"required,min=1,max=1000" required:"true" minimum:"1" maximum:"1000" description:"优先级(数字越小优先级越高)"`
RealnameCheckInterval *int `json:"realname_check_interval" validate:"omitempty,min=30" minimum:"30" description:"实名检查间隔NULL表示不检查最小30秒"`
CarddataCheckInterval *int `json:"carddata_check_interval" validate:"omitempty,min=60" minimum:"60" description:"流量检查间隔NULL表示不检查最小60秒"`
PackageCheckInterval *int `json:"package_check_interval" validate:"omitempty,min=60" minimum:"60" description:"套餐检查间隔NULL表示不检查最小60秒"`
Description string `json:"description" validate:"omitempty,max=500" maxLength:"500" description:"配置说明"`
}
// UpdatePollingConfigRequest 更新轮询配置请求
type UpdatePollingConfigRequest struct {
ConfigName *string `json:"config_name" validate:"omitempty,min=1,max=100" minLength:"1" maxLength:"100" description:"配置名称"`
CardCondition *string `json:"card_condition" validate:"omitempty,oneof=not_real_name real_name activated suspended" description:"卡状态条件 (not_real_name:未实名, real_name:已实名, activated:已激活, suspended:已停用)"`
CardCategory *string `json:"card_category" validate:"omitempty,oneof=normal industry" description:"卡业务类型 (normal:普通卡, industry:行业卡)"`
CarrierID *uint `json:"carrier_id" validate:"omitempty" description:"运营商ID可选精确匹配"`
Priority *int `json:"priority" validate:"omitempty,min=1,max=1000" minimum:"1" maximum:"1000" description:"优先级(数字越小优先级越高)"`
RealnameCheckInterval *int `json:"realname_check_interval" validate:"omitempty,min=30" minimum:"30" description:"实名检查间隔NULL表示不检查最小30秒"`
CarddataCheckInterval *int `json:"carddata_check_interval" validate:"omitempty,min=60" minimum:"60" description:"流量检查间隔NULL表示不检查最小60秒"`
PackageCheckInterval *int `json:"package_check_interval" validate:"omitempty,min=60" minimum:"60" description:"套餐检查间隔NULL表示不检查最小60秒"`
Description *string `json:"description" validate:"omitempty,max=500" maxLength:"500" description:"配置说明"`
}
// PollingConfigListRequest 轮询配置列表请求
type PollingConfigListRequest struct {
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
Status *int16 `json:"status" query:"status" validate:"omitempty,oneof=0 1" description:"状态 (1:启用, 0:禁用)"`
CardCondition *string `json:"card_condition" query:"card_condition" validate:"omitempty,oneof=not_real_name real_name activated suspended" description:"卡状态条件"`
CardCategory *string `json:"card_category" query:"card_category" validate:"omitempty,oneof=normal industry" description:"卡业务类型"`
CarrierID *uint `json:"carrier_id" query:"carrier_id" validate:"omitempty" description:"运营商ID"`
ConfigName *string `json:"config_name" query:"config_name" validate:"omitempty,max=100" maxLength:"100" description:"配置名称(模糊搜索)"`
}
// UpdatePollingConfigStatusRequest 更新轮询配置状态请求
type UpdatePollingConfigStatusRequest struct {
Status int16 `json:"status" validate:"required,oneof=0 1" required:"true" description:"状态 (1:启用, 0:禁用)"`
}
// PollingConfigResponse 轮询配置响应
type PollingConfigResponse struct {
ID uint `json:"id" description:"配置ID"`
ConfigName string `json:"config_name" description:"配置名称"`
CardCondition string `json:"card_condition" description:"卡状态条件 (not_real_name:未实名, real_name:已实名, activated:已激活, suspended:已停用)"`
CardCategory string `json:"card_category" description:"卡业务类型 (normal:普通卡, industry:行业卡)"`
CarrierID *uint `json:"carrier_id" description:"运营商ID"`
Priority int `json:"priority" description:"优先级(数字越小优先级越高)"`
RealnameCheckInterval *int `json:"realname_check_interval" description:"实名检查间隔NULL表示不检查"`
CarddataCheckInterval *int `json:"carddata_check_interval" description:"流量检查间隔NULL表示不检查"`
PackageCheckInterval *int `json:"package_check_interval" description:"套餐检查间隔NULL表示不检查"`
Status int16 `json:"status" description:"状态 (1:启用, 0:禁用)"`
Description string `json:"description" description:"配置说明"`
CreatedAt string `json:"created_at" description:"创建时间"`
UpdatedAt string `json:"updated_at" description:"更新时间"`
}
// UpdatePollingConfigParams 更新轮询配置参数
type UpdatePollingConfigParams struct {
IDReq
UpdatePollingConfigRequest
}
// UpdatePollingConfigStatusParams 更新轮询配置状态参数
type UpdatePollingConfigStatusParams struct {
IDReq
UpdatePollingConfigStatusRequest
}
// PollingConfigPageResult 轮询配置分页结果
type PollingConfigPageResult struct {
List []*PollingConfigResponse `json:"list" description:"配置列表"`
Total int64 `json:"total" description:"总数"`
Page int `json:"page" description:"当前页"`
PageSize int `json:"page_size" description:"每页数量"`
TotalPages int `json:"total_pages" description:"总页数"`
}

View File

@@ -0,0 +1,72 @@
package dto
import "time"
// TriggerSingleReq 单卡手动触发请求
type TriggerSingleReq struct {
CardID uint `json:"card_id" validate:"required" description:"卡ID"`
TaskType string `json:"task_type" validate:"required,oneof=polling:realname polling:carddata polling:package" description:"任务类型"`
}
// TriggerBatchReq 批量手动触发请求
type TriggerBatchReq struct {
CardIDs []uint `json:"card_ids" validate:"required,min=1,max=1000" description:"卡ID列表最多1000个"`
TaskType string `json:"task_type" validate:"required,oneof=polling:realname polling:carddata polling:package" description:"任务类型"`
}
// TriggerByConditionReq 条件筛选触发请求
type TriggerByConditionReq struct {
TaskType string `json:"task_type" validate:"required,oneof=polling:realname polling:carddata polling:package" description:"任务类型"`
CardStatus string `json:"card_status" validate:"omitempty" description:"卡状态筛选"`
CarrierCode string `json:"carrier_code" validate:"omitempty" description:"运营商代码筛选"`
CardType string `json:"card_type" validate:"omitempty" description:"卡类型筛选"`
ShopID *uint `json:"shop_id" validate:"omitempty" description:"店铺ID筛选"`
PackageIDs []uint `json:"package_ids" validate:"omitempty" description:"套餐ID列表筛选"`
EnablePolling *bool `json:"enable_polling" validate:"omitempty" description:"是否启用轮询筛选"`
Limit int `json:"limit" validate:"omitempty,min=1,max=1000" description:"限制数量最多1000"`
}
// CancelTriggerReq 取消触发请求
type CancelTriggerReq struct {
TriggerID uint `json:"trigger_id" validate:"required" description:"触发任务ID"`
}
// ManualTriggerLogResp 手动触发日志响应
type ManualTriggerLogResp struct {
ID uint `json:"id" description:"日志ID"`
TaskType string `json:"task_type" description:"任务类型"`
TaskTypeName string `json:"task_type_name" description:"任务类型名称"`
TriggerType string `json:"trigger_type" description:"触发类型single/batch/by_condition"`
TriggerTypeName string `json:"trigger_type_name" description:"触发类型名称"`
TotalCount int `json:"total_count" description:"总卡数"`
ProcessedCount int `json:"processed_count" description:"已处理数"`
SuccessCount int `json:"success_count" description:"成功数"`
FailedCount int `json:"failed_count" description:"失败数"`
Status string `json:"status" description:"状态pending/processing/completed/cancelled"`
StatusName string `json:"status_name" description:"状态名称"`
TriggeredBy uint `json:"triggered_by" description:"触发人ID"`
TriggeredAt time.Time `json:"triggered_at" description:"触发时间"`
CompletedAt *time.Time `json:"completed_at,omitempty" description:"完成时间"`
}
// ManualTriggerLogListResp 手动触发日志列表响应
type ManualTriggerLogListResp struct {
Items []*ManualTriggerLogResp `json:"items" description:"日志列表"`
Total int64 `json:"total" description:"总数"`
Page int `json:"page" description:"当前页"`
PageSize int `json:"page_size" description:"每页数量"`
TotalPages int `json:"total_pages" description:"总页数"`
}
// ListManualTriggerLogReq 查询手动触发日志请求
type ListManualTriggerLogReq struct {
TaskType string `json:"task_type" query:"task_type" description:"任务类型筛选"`
Page int `json:"page" query:"page" validate:"omitempty,min=1" description:"页码"`
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" description:"每页数量"`
}
// ManualTriggerStatusResp 手动触发状态响应
type ManualTriggerStatusResp struct {
RunningTasks []*ManualTriggerLogResp `json:"running_tasks" description:"正在运行的任务"`
QueueSizes map[string]int64 `json:"queue_sizes" description:"各队列大小"`
}

View File

@@ -0,0 +1,55 @@
package dto
import "time"
// PollingOverviewResp 轮询总览响应
type PollingOverviewResp struct {
TotalCards int64 `json:"total_cards" description:"总卡数"`
InitializedCards int64 `json:"initialized_cards" description:"已初始化卡数"`
InitProgress float64 `json:"init_progress" description:"初始化进度0-100"`
IsInitializing bool `json:"is_initializing" description:"是否正在初始化"`
RealnameQueueSize int64 `json:"realname_queue_size" description:"实名检查队列大小"`
CarddataQueueSize int64 `json:"carddata_queue_size" description:"流量检查队列大小"`
PackageQueueSize int64 `json:"package_queue_size" description:"套餐检查队列大小"`
}
// PollingQueueStatusResp 队列状态响应
type PollingQueueStatusResp struct {
TaskType string `json:"task_type" description:"任务类型"`
TaskTypeName string `json:"task_type_name" description:"任务类型名称"`
QueueSize int64 `json:"queue_size" description:"队列大小"`
ManualPending int64 `json:"manual_pending" description:"手动触发待处理数"`
DueCount int64 `json:"due_count" description:"到期待处理数"`
AvgWaitTime float64 `json:"avg_wait_time_s" description:"平均等待时间(秒)"`
}
// PollingQueueStatusListResp 队列状态列表响应
type PollingQueueStatusListResp struct {
Items []*PollingQueueStatusResp `json:"items" description:"队列状态列表"`
}
// PollingTaskStatsResp 任务统计响应
type PollingTaskStatsResp struct {
TaskType string `json:"task_type" description:"任务类型"`
TaskTypeName string `json:"task_type_name" description:"任务类型名称"`
SuccessCount1h int64 `json:"success_count_1h" description:"1小时成功数"`
FailureCount1h int64 `json:"failure_count_1h" description:"1小时失败数"`
TotalCount1h int64 `json:"total_count_1h" description:"1小时总数"`
SuccessRate float64 `json:"success_rate" description:"成功率0-100"`
AvgDurationMs float64 `json:"avg_duration_ms" description:"平均耗时(毫秒)"`
}
// PollingTaskStatsListResp 任务统计列表响应
type PollingTaskStatsListResp struct {
Items []*PollingTaskStatsResp `json:"items" description:"任务统计列表"`
}
// PollingInitProgressResp 初始化进度响应
type PollingInitProgressResp struct {
TotalCards int64 `json:"total_cards" description:"总卡数"`
InitializedCards int64 `json:"initialized_cards" description:"已初始化卡数"`
Progress float64 `json:"progress" description:"进度百分比0-100"`
IsComplete bool `json:"is_complete" description:"是否完成"`
StartedAt time.Time `json:"started_at" description:"开始时间"`
EstimatedETA string `json:"estimated_eta" description:"预计完成时间"`
}

View File

@@ -32,6 +32,9 @@ type IotCard struct {
RealNameStatus int `gorm:"column:real_name_status;type:int;default:0;not null;comment:实名状态 0-未实名 1-已实名(行业卡可以保持0)" json:"real_name_status"`
NetworkStatus int `gorm:"column:network_status;type:int;default:0;not null;comment:网络状态 0-停机 1-开机" json:"network_status"`
DataUsageMB int64 `gorm:"column:data_usage_mb;type:bigint;default:0;comment:累计流量使用(MB)" json:"data_usage_mb"`
CurrentMonthUsageMB float64 `gorm:"column:current_month_usage_mb;type:decimal(10,2);default:0;comment:本月已用流量(MB) - Gateway返回的自然月流量总量" json:"current_month_usage_mb"`
CurrentMonthStartDate *time.Time `gorm:"column:current_month_start_date;type:date;comment:本月开始日期 - 用于检测跨月流量重置" json:"current_month_start_date"`
LastMonthTotalMB float64 `gorm:"column:last_month_total_mb;type:decimal(10,2);default:0;comment:上月结束时的总流量(MB) - 用于跨月流量计算" json:"last_month_total_mb"`
EnablePolling bool `gorm:"column:enable_polling;type:boolean;default:true;comment:是否参与轮询 true-参与 false-不参与" json:"enable_polling"`
LastDataCheckAt *time.Time `gorm:"column:last_data_check_at;comment:最后一次流量检查时间" json:"last_data_check_at"`
LastRealNameCheckAt *time.Time `gorm:"column:last_real_name_check_at;comment:最后一次实名检查时间" json:"last_real_name_check_at"`

View File

@@ -1,29 +1,152 @@
package model
import (
"gorm.io/gorm"
"time"
)
// PollingConfig 轮询配置模型
// 支持梯度轮询策略(实名检查、卡流量检查、套餐流量检查)
// PollingConfig 轮询配置
type PollingConfig struct {
gorm.Model
BaseModel `gorm:"embedded"`
ConfigName string `gorm:"column:config_name;type:varchar(100);uniqueIndex:idx_polling_config_name,where:deleted_at IS NULL;not null;comment:配置名称(如 未实名卡、实名卡)" json:"config_name"`
Description string `gorm:"column:description;type:varchar(500);comment:配置描述" json:"description"`
CardCondition string `gorm:"column:card_condition;type:varchar(50);comment:卡状态条件 not_real_name-未实名 real_name-已实名 activated-已激活 suspended-已停用" json:"card_condition"`
CarrierID uint `gorm:"column:carrier_id;index;comment:运营商ID(NULL表示所有运营商)" json:"carrier_id"`
RealNameCheckEnabled bool `gorm:"column:real_name_check_enabled;type:boolean;default:false;comment:是否启用实名检查" json:"real_name_check_enabled"`
RealNameCheckInterval int `gorm:"column:real_name_check_interval;type:int;default:60;comment:实名检查间隔(秒)" json:"real_name_check_interval"`
CardDataCheckEnabled bool `gorm:"column:card_data_check_enabled;type:boolean;default:false;comment:是否启用卡流量检查" json:"card_data_check_enabled"`
CardDataCheckInterval int `gorm:"column:card_data_check_interval;type:int;default:60;comment:卡流量检查间隔(秒)" json:"card_data_check_interval"`
PackageCheckEnabled bool `gorm:"column:package_check_enabled;type:boolean;default:false;comment:是否启用套餐流量检查" json:"package_check_enabled"`
PackageCheckInterval int `gorm:"column:package_check_interval;type:int;default:60;comment:套餐流量检查间隔(秒)" json:"package_check_interval"`
Priority int `gorm:"column:priority;type:int;default:100;not null;comment:优先级(数字越小优先级越高)" json:"priority"`
Status int `gorm:"column:status;type:int;default:1;not null;comment:状态 1-启用 2-禁用" json:"status"`
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
ConfigName string `gorm:"column:config_name;type:varchar(100);not null;comment:配置名称" json:"config_name"`
CardCondition string `gorm:"column:card_condition;type:varchar(50);comment:卡状态条件not_real_name/real_name/activated/suspended" json:"card_condition"`
CardCategory string `gorm:"column:card_category;type:varchar(50);comment:卡业务类型normal/industry" json:"card_category"`
CarrierID *uint `gorm:"column:carrier_id;comment:运营商ID可选精确匹配" json:"carrier_id"`
Priority int `gorm:"column:priority;not null;default:100;comment:优先级(数字越小优先级越高)" json:"priority"`
RealnameCheckInterval *int `gorm:"column:realname_check_interval;comment:实名检查间隔NULL表示不检查" json:"realname_check_interval"`
CarddataCheckInterval *int `gorm:"column:carddata_check_interval;comment:流量检查间隔NULL表示不检查" json:"carddata_check_interval"`
PackageCheckInterval *int `gorm:"column:package_check_interval;comment:套餐检查间隔NULL表示不检查" json:"package_check_interval"`
Status int16 `gorm:"column:status;type:smallint;not null;default:1;comment:状态0-禁用1-启用" json:"status"`
Description string `gorm:"column:description;type:text;comment:配置说明" json:"description"`
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"`
CreatedBy *uint `gorm:"column:created_by;comment:创建人ID" json:"created_by"`
UpdatedBy *uint `gorm:"column:updated_by;comment:更新人ID" json:"updated_by"`
}
// TableName 指定表名
func (PollingConfig) TableName() string {
return "tb_polling_config"
}
// PollingConcurrencyConfig 并发控制配置表
type PollingConcurrencyConfig struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
TaskType string `gorm:"column:task_type;type:varchar(50);uniqueIndex;not null;comment:任务类型realname/carddata/package/stop_start" json:"task_type"`
MaxConcurrency int `gorm:"column:max_concurrency;not null;default:50;comment:最大并发数" json:"max_concurrency"`
Description string `gorm:"column:description;type:text;comment:配置说明" json:"description"`
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"`
UpdatedBy *uint `gorm:"column:updated_by;comment:更新人ID" json:"updated_by"`
}
// TableName 指定表名
func (PollingConcurrencyConfig) TableName() string {
return "tb_polling_concurrency_config"
}
// PollingAlertRule 告警规则表
type PollingAlertRule struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
RuleName string `gorm:"column:rule_name;type:varchar(100);not null;comment:规则名称" json:"rule_name"`
TaskType string `gorm:"column:task_type;type:varchar(50);not null;comment:任务类型realname/carddata/package" json:"task_type"`
MetricType string `gorm:"column:metric_type;type:varchar(50);not null;comment:指标类型queue_size/success_rate/avg_duration/concurrency" json:"metric_type"`
Operator string `gorm:"column:operator;type:varchar(20);not null;comment:比较运算符gt/lt/gte/lte/eq" json:"operator"`
Threshold float64 `gorm:"column:threshold;type:decimal(10,2);not null;comment:阈值" json:"threshold"`
DurationMinutes int `gorm:"column:duration_minutes;not null;default:5;comment:持续时长(分钟),避免短暂波动" json:"duration_minutes"`
AlertLevel string `gorm:"column:alert_level;type:varchar(20);not null;default:'warning';comment:告警级别info/warning/error/critical" json:"alert_level"`
NotificationChannels string `gorm:"column:notification_channels;type:text;comment:通知渠道JSON数组[\"email\",\"sms\",\"webhook\"]" json:"notification_channels"`
NotificationConfig string `gorm:"column:notification_config;type:text;comment:通知配置JSON" json:"notification_config"`
Status int16 `gorm:"column:status;type:smallint;not null;default:1;comment:状态0-禁用1-启用" json:"status"`
CooldownMinutes int `gorm:"column:cooldown_minutes;not null;default:5;comment:冷却期(分钟),避免重复告警" json:"cooldown_minutes"`
Description string `gorm:"column:description;type:text;comment:规则说明" json:"description"`
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"`
CreatedBy *uint `gorm:"column:created_by;comment:创建人ID" json:"created_by"`
UpdatedBy *uint `gorm:"column:updated_by;comment:更新人ID" json:"updated_by"`
}
// TableName 指定表名
func (PollingAlertRule) TableName() string {
return "tb_polling_alert_rule"
}
// PollingAlertHistory 告警历史表
type PollingAlertHistory struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
RuleID uint `gorm:"column:rule_id;not null;comment:告警规则ID" json:"rule_id"`
TaskType string `gorm:"column:task_type;type:varchar(50);not null;comment:任务类型" json:"task_type"`
MetricType string `gorm:"column:metric_type;type:varchar(50);not null;comment:指标类型" json:"metric_type"`
AlertLevel string `gorm:"column:alert_level;type:varchar(20);not null;comment:告警级别" json:"alert_level"`
CurrentValue float64 `gorm:"column:current_value;type:decimal(10,2);not null;comment:当前值" json:"current_value"`
Threshold float64 `gorm:"column:threshold;type:decimal(10,2);not null;comment:阈值" json:"threshold"`
AlertMessage string `gorm:"column:alert_message;type:text;not null;comment:告警消息" json:"alert_message"`
NotificationChannels string `gorm:"column:notification_channels;type:text;comment:通知渠道JSON数组" json:"notification_channels"`
NotificationStatus string `gorm:"column:notification_status;type:varchar(20);comment:通知状态pending/sent/failed" json:"notification_status"`
NotificationResult string `gorm:"column:notification_result;type:text;comment:通知结果JSON" json:"notification_result"`
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:告警时间" json:"created_at"`
}
// TableName 指定表名
func (PollingAlertHistory) TableName() string {
return "tb_polling_alert_history"
}
// DataCleanupConfig 数据清理配置表
type DataCleanupConfig struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
TargetTable string `gorm:"column:table_name;type:varchar(100);uniqueIndex;not null;comment:表名" json:"table_name"`
RetentionDays int `gorm:"column:retention_days;not null;comment:保留天数" json:"retention_days"`
Enabled int16 `gorm:"column:enabled;type:smallint;not null;default:1;comment:是否启用0-禁用1-启用" json:"enabled"`
BatchSize int `gorm:"column:batch_size;not null;default:10000;comment:每批删除条数" json:"batch_size"`
Description string `gorm:"column:description;type:text;comment:配置说明" json:"description"`
CreatedAt time.Time `gorm:"column:created_at;not null;default:CURRENT_TIMESTAMP;comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;not null;default:CURRENT_TIMESTAMP;comment:更新时间" json:"updated_at"`
UpdatedBy *uint `gorm:"column:updated_by;comment:更新人ID" json:"updated_by"`
}
// TableName 指定表名
func (DataCleanupConfig) TableName() string {
return "tb_data_cleanup_config"
}
// DataCleanupLog 数据清理日志表
type DataCleanupLog struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
TargetTable string `gorm:"column:table_name;type:varchar(100);not null;comment:表名" json:"table_name"`
CleanupType string `gorm:"column:cleanup_type;type:varchar(50);not null;comment:清理类型scheduled/manual" json:"cleanup_type"`
RetentionDays int `gorm:"column:retention_days;not null;comment:保留天数" json:"retention_days"`
DeletedCount int64 `gorm:"column:deleted_count;not null;default:0;comment:删除记录数" json:"deleted_count"`
DurationMs int64 `gorm:"column:duration_ms;not null;default:0;comment:执行耗时(毫秒)" json:"duration_ms"`
Status string `gorm:"column:status;type:varchar(20);not null;comment:状态success/failed/running" json:"status"`
ErrorMessage string `gorm:"column:error_message;type:text;comment:错误信息" json:"error_message"`
StartedAt time.Time `gorm:"column:started_at;not null;comment:开始时间" json:"started_at"`
CompletedAt *time.Time `gorm:"column:completed_at;comment:完成时间" json:"completed_at"`
TriggeredBy *uint `gorm:"column:triggered_by;comment:触发人ID手动触发时" json:"triggered_by"`
}
// TableName 指定表名
func (DataCleanupLog) TableName() string {
return "tb_data_cleanup_log"
}
// PollingManualTriggerLog 手动触发日志表
type PollingManualTriggerLog struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
TaskType string `gorm:"column:task_type;type:varchar(50);not null;comment:任务类型realname/carddata/package" json:"task_type"`
TriggerType string `gorm:"column:trigger_type;type:varchar(50);not null;comment:触发类型single/batch/by_condition" json:"trigger_type"`
CardIDs string `gorm:"column:card_ids;type:text;comment:卡ID列表JSON数组" json:"card_ids"`
ConditionFilter string `gorm:"column:condition_filter;type:text;comment:筛选条件JSON" json:"condition_filter"`
TotalCount int `gorm:"column:total_count;not null;default:0;comment:总卡数" json:"total_count"`
ProcessedCount int `gorm:"column:processed_count;not null;default:0;comment:已处理数" json:"processed_count"`
SuccessCount int `gorm:"column:success_count;not null;default:0;comment:成功数" json:"success_count"`
FailedCount int `gorm:"column:failed_count;not null;default:0;comment:失败数" json:"failed_count"`
Status string `gorm:"column:status;type:varchar(20);not null;comment:状态pending/processing/completed/cancelled" json:"status"`
TriggeredBy uint `gorm:"column:triggered_by;not null;comment:触发人ID" json:"triggered_by"`
TriggeredAt time.Time `gorm:"column:triggered_at;not null;default:CURRENT_TIMESTAMP;comment:触发时间" json:"triggered_at"`
CompletedAt *time.Time `gorm:"column:completed_at;comment:完成时间" json:"completed_at"`
}
// TableName 指定表名
func (PollingManualTriggerLog) TableName() string {
return "tb_polling_manual_trigger_log"
}