Files
junhong_cmp_fiber/internal/model/polling.go
邹进 98017ac053
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m37s
feat: 分层轮询、重置日前加密与激活前流量结算
- 轮询配置新增套餐状态、资产状态、重置日前窗口与窗口内流量间隔(迁移 248),间隔三态:正数按间隔、0 不检查、空继承
- 配置按 priority, id 排序合并;在库与已销售无套餐未匹配时告警不入队
- 新增优先级整体重排、匹配预览、立即重算到期时间(异步只提前)、分层统计与重置日前加密统计接口
- 已切换日快照计量的卡流量按观测时间归属,激活前用量只记已结算
- 订单购买与实名激活补齐资产级激活锁,激活前对已切换卡结算一次流量,失败只告警不阻塞,结算不触发通道阈值判定
2026-10-24 17:06:38 +09:00

215 lines
18 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"time"
"gorm.io/gorm"
)
// PollingConfig 轮询配置表
type PollingConfig struct {
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:实名检查间隔(秒):正数按间隔,0不检查(停止继承),NULL继承" json:"realname_check_interval"`
CarddataCheckInterval *int `gorm:"column:carddata_check_interval;comment:流量检查间隔(秒):正数按间隔,0不检查(停止继承),NULL继承" json:"carddata_check_interval"`
PackageCheckInterval *int `gorm:"column:package_check_interval;comment:套餐检查间隔(秒):正数按间隔,0不检查(停止继承),NULL继承" json:"package_check_interval"`
ProtectCheckInterval *int `gorm:"column:protect_check_interval;comment:保护期一致性检查间隔(秒),NULL=不参与" json:"protect_check_interval"`
CardStatusCheckInterval *int `gorm:"column:card_status_check_interval;comment:卡状态检查间隔(秒):正数按间隔,0不检查(停止继承),NULL继承" json:"card_status_check_interval"`
PackageState *string `gorm:"column:package_state;type:varchar(20);comment:套餐状态匹配:active/depleted/pending/none,NULL不限" json:"package_state"`
AssetStatus *int `gorm:"column:asset_status;type:smallint;comment:资产状态匹配:1在库 2已销售 3已换货 4已停用,NULL不限" json:"asset_status"`
PreResetWindow *int `gorm:"column:pre_reset_window;comment:重置日前加密窗口长度(秒),NULL不加密" json:"pre_reset_window"`
PreResetCarddataInterval *int `gorm:"column:pre_reset_carddata_interval;comment:重置日前窗口内流量检查间隔(秒),NULL不加密" json:"pre_reset_carddata_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/protect/card_status" 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"
}
// PollingPriorityItem 是「某卡某轮询任务类型被加急」的持久化事实。
//
// 活动项粒度为 (card_id, task_type),由部分唯一索引保证至多一条:Status 取
// pending-待执行 / processing-执行中 时为活动项,取
// completed-已完成 / failed-失败出队 / closed-人工关闭 / expired-有效期到期 时为终态,
// 终态行不占用唯一键。TriggerType 是首次触发场景,TriggerTypes 是去重后的全部触发场景集合;
// ClaimedAt 是认领租约基准,AttemptCount 只在真正发起执行后累加,Result 与 FailureReason
// 只承载可安全展示的结果与原因,ShopIDSnapshot 是消费时点解析的卡所属店铺快照(平台卡为 NULL),
// 读侧数据范围按它下推,卡改归属不追溯已入队的加急事实。
//
// 资产身份(AssetType/AssetID)与设备号、代理归属同样在入队时冻结:卡绑定有效设备时资产为
// 该设备,独立卡为卡自身;AgentShopIDSnapshot 是卡所属店铺的直接上级代理店铺(一级代理与平台卡为空)。
// AttemptLimit 取代码常量,既有行随数据库默认值获得上限。StartedAt/FinishedAt 只在真正发起执行
// 后写入,NextRunAt 是下一次计划执行时间(未排期为 NULL,读侧 MUST NOT 据此判定已过期),
// DequeuedAt 在任一终态写入,PriorityEffectiveFrom 是有效期起算时间(新增行取入队时间)。
// IntegrationLogID 只保存集成交互日志标识,不复制凭证或响应原文。
// 本模型不声明任何关联标签与数据库外键,关联一律只存 ID 并由应用层显式查询。
type PollingPriorityItem struct {
gorm.Model
CardID uint `gorm:"column:card_id;type:bigint;not null" json:"card_id"`
TaskType string `gorm:"column:task_type;type:varchar(50);not null" json:"task_type"`
Status string `gorm:"column:status;type:varchar(16);not null;default:'pending'" json:"status"`
TriggerType string `gorm:"column:trigger_type;type:varchar(30);not null" json:"trigger_type"`
TriggerTypes string `gorm:"column:trigger_types;type:varchar(255);not null;default:''" json:"trigger_types"`
TriggerCount int `gorm:"column:trigger_count;type:int;not null;default:1" json:"trigger_count"`
LastTriggeredAt time.Time `gorm:"column:last_triggered_at;type:timestamptz;not null;default:now()" json:"last_triggered_at"`
SourceOrderID *uint `gorm:"column:source_order_id;type:bigint" json:"source_order_id,omitempty"`
SourcePackageUsageID *uint `gorm:"column:source_package_usage_id;type:bigint" json:"source_package_usage_id,omitempty"`
AttemptCount int `gorm:"column:attempt_count;type:int;not null;default:0" json:"attempt_count"`
AttemptLimit int `gorm:"column:attempt_limit;type:int;not null;default:3" json:"attempt_limit"`
ClaimedAt *time.Time `gorm:"column:claimed_at;type:timestamptz" json:"claimed_at,omitempty"`
StartedAt *time.Time `gorm:"column:started_at;type:timestamptz" json:"started_at,omitempty"`
FinishedAt *time.Time `gorm:"column:finished_at;type:timestamptz" json:"finished_at,omitempty"`
NextRunAt *time.Time `gorm:"column:next_run_at;type:timestamptz" json:"next_run_at,omitempty"`
DequeuedAt *time.Time `gorm:"column:dequeued_at;type:timestamptz" json:"dequeued_at,omitempty"`
IntegrationLogID string `gorm:"column:integration_log_id;type:varchar(64);not null;default:''" json:"integration_log_id"`
PriorityEffectiveFrom *time.Time `gorm:"column:priority_effective_from;type:timestamptz" json:"priority_effective_from,omitempty"`
ManualReason string `gorm:"column:manual_reason;type:varchar(500);not null;default:''" json:"manual_reason"`
ManualOperatorID uint `gorm:"column:manual_operator_id;type:bigint;not null;default:0" json:"manual_operator_id"`
ManualOperatorName string `gorm:"column:manual_operator_name;type:varchar(100);not null;default:''" json:"manual_operator_name"`
ShopIDSnapshot *uint `gorm:"column:shop_id_snapshot;type:bigint" json:"shop_id_snapshot,omitempty"`
AgentShopIDSnapshot *uint `gorm:"column:agent_shop_id_snapshot;type:bigint" json:"agent_shop_id_snapshot,omitempty"`
AssetType string `gorm:"column:asset_type;type:varchar(20);not null;default:''" json:"asset_type"`
AssetID *uint `gorm:"column:asset_id;type:bigint" json:"asset_id,omitempty"`
DeviceNoSnapshot string `gorm:"column:device_no_snapshot;type:varchar(100);not null;default:''" json:"device_no_snapshot"`
Result string `gorm:"column:result;type:varchar(16);not null;default:''" json:"result"`
FailureReason string `gorm:"column:failure_reason;type:varchar(500);not null;default:''" json:"failure_reason"`
}
// TableName 指定表名
func (PollingPriorityItem) TableName() string {
return "tb_polling_priority_item"
}