Files
junhong_cmp_fiber/internal/model/polling.go
huang 18daeae65a
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m17s
feat: 钱包系统分离 - 代理钱包与卡钱包完全隔离
## 变更概述
将统一钱包系统拆分为代理钱包和卡钱包两个独立系统,实现数据表和代码层面的完全隔离。

## 数据库变更
- 新增 6 张表:tb_agent_wallet、tb_agent_wallet_transaction、tb_agent_recharge_record、tb_card_wallet、tb_card_wallet_transaction、tb_card_recharge_record
- 删除 3 张旧表:tb_wallet、tb_wallet_transaction、tb_recharge_record
- 代理钱包:按 (shop_id, wallet_type) 唯一标识,支持主钱包和分佣钱包
- 卡钱包:按 (resource_type, resource_id) 唯一标识,支持物联网卡和设备

## 代码变更
- Model 层:新增 AgentWallet、AgentWalletTransaction、AgentRechargeRecord、CardWallet、CardWalletTransaction、CardRechargeRecord 模型
- Store 层:新增 6 个独立 Store,支持事务、乐观锁、Redis 缓存
- Service 层:重构 commission_calculation、commission_withdrawal、order、recharge 等 8 个服务
- Bootstrap 层:更新 Store 和 Service 依赖注入
- 常量层:按钱包类型重新组织常量和 Redis Key 生成函数

## 技术特性
- 乐观锁:使用 version 字段防止并发冲突
- 多租户:支持 shop_id_tag 和 enterprise_id_tag 过滤
- 事务管理:所有余额变动使用事务保证 ACID
- 缓存策略:Cache-Aside 模式,余额变动后删除缓存

## 业务影响
- 代理钱包和卡钱包业务完全隔离,互不影响
- 为独立监控、优化、扩展打下基础
- 提升代理钱包的稳定性和独立性

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-25 09:51:00 +08:00

153 lines
12 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"
)
// 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:实名检查间隔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"
}