新增 000228 迁移:规则表 tb_package_traffic_alert_rule(每套餐商品至多一条,无软删除,package_id 非部分唯一约束)、达量预警快照表 tb_package_traffic_alert(以主套餐使用记录 + 阈值快照为唯一键, 触发时冻结用量、额度、比例、阈值、到期时间、归属与资产快照),并为 tb_package_usage 新增扫描 范围部分索引 idx_package_usage_alert_scope;down 在预警表存在数据时阻断回滚。 新增规则维护接口 GET/POST/PUT /api/admin/package-traffic-alert-rules(仅超级管理员与平台账号): 创建校验套餐存在且真流量额度大于零,阈值为 1%~100% 的两位小数;修改只影响后续扫描,不回填也 不改写既有预警快照;全部写操作记录操作者、前后值与时间。 新增每日 06:00(Asia/Shanghai)扫描任务 package:traffic:alert:scan,与套餐临期扫描共用 data_cleanup 队列:按资产汇总当前有效套餐的真流量,分子取使用记录真已用量、分母取使用记录真总量快照,命中 主套餐规则阈值时在同一事务创建预警与可靠通知事件;重复执行以唯一冲突视为已处理,不重复投递, 不建停机锁、不调用运营商。 新增预警列表、详情与异步导出 GET /api/admin/package-traffic-alerts、GET /api/admin/package-traffic-alerts/:id、 POST /api/admin/package-traffic-alerts/export,列表与详情一律读冻结快照;新增通知类型 package.traffic.alert 与受控目标 package_traffic_alert_detail,目标解析仅对超级管理员与平台账号 返回可跳转,越权与不存在统一按资源不可见处理。 同步 OpenAPI(cmd/gendocs、cmd/api/docs.go、pkg/openapi/handlers.go)、审计动作与资源注册、上下文 健康检查证据;归档变更并同步 package-traffic-alert 主 Spec。
95 lines
7.6 KiB
Go
95 lines
7.6 KiB
Go
package model
|
||
|
||
import (
|
||
"time"
|
||
)
|
||
|
||
// PackageTrafficAlertRule 套餐真流量预警规则模型。
|
||
// 每个套餐商品至多一条当前规则(package_id 唯一),只提供创建、修改阈值与启停,不提供删除;
|
||
// 规则变更只影响后续扫描,已产生的预警快照不被改写。
|
||
// 表内不设软删除列:停用由 enabled 表达,唯一约束因此可用非部分索引,规避部分索引与 OnConflict 的谓词问题。
|
||
type PackageTrafficAlertRule struct {
|
||
// ID 主键。
|
||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||
BaseModel `gorm:"embedded"`
|
||
// PackageID 套餐商品ID;唯一约束保证每个商品至多一条当前规则。
|
||
PackageID uint `gorm:"column:package_id;type:bigint;not null;uniqueIndex:uq_package_traffic_alert_rule_package;comment:套餐商品ID" json:"package_id"`
|
||
// ThresholdPercent 真流量预警阈值百分比,取值 1~100,允许两位小数。
|
||
ThresholdPercent float64 `gorm:"column:threshold_percent;type:numeric(5,2);not null;comment:真流量预警阈值百分比 1~100" json:"threshold_percent"`
|
||
// Enabled 状态 0-禁用 1-启用;停用后扫描不再创建新预警。
|
||
Enabled int `gorm:"column:enabled;type:smallint;not null;default:0;comment:状态 0-禁用 1-启用" json:"enabled"`
|
||
// Remark 备注,最多 500 字符。
|
||
Remark string `gorm:"column:remark;type:varchar(500);not null;default:'';comment:备注" json:"remark"`
|
||
// CreatedAt 创建时间。
|
||
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
|
||
// UpdatedAt 最近更新时间,阈值修改与启停均刷新。
|
||
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null;autoUpdateTime" json:"updated_at"`
|
||
}
|
||
|
||
// TableName 返回套餐真流量预警规则表名。
|
||
func (PackageTrafficAlertRule) TableName() string {
|
||
return "tb_package_traffic_alert_rule"
|
||
}
|
||
|
||
// PackageTrafficAlert 套餐真流量达量预警事实模型。
|
||
// 唯一键为「主套餐使用记录 + 阈值快照」;触发时的阈值、汇总用量、资产与归属快照一律冻结,
|
||
// 后续归属或绑定变化不得改写本行,导出与列表只读这些快照列。
|
||
type PackageTrafficAlert struct {
|
||
// ID 主键。
|
||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||
BaseModel `gorm:"embedded"`
|
||
// PackageUsageID 主套餐使用记录ID(master_usage_id 为空且按优先级/生效时间/编号取第一条)。
|
||
PackageUsageID uint `gorm:"column:package_usage_id;type:bigint;not null;uniqueIndex:uq_package_traffic_alert_usage_threshold,priority:1;comment:主套餐使用记录ID" json:"package_usage_id"`
|
||
// PackageID 阈值来源的套餐商品ID快照。
|
||
PackageID uint `gorm:"column:package_id;type:bigint;not null;comment:阈值来源套餐商品ID" json:"package_id"`
|
||
// RuleID 触发时的规则ID快照。
|
||
RuleID uint `gorm:"column:rule_id;type:bigint;not null;comment:触发时规则ID" json:"rule_id"`
|
||
// AssetType 资产类型 iot_card/device。
|
||
AssetType string `gorm:"column:asset_type;type:varchar(16);not null;comment:资产类型 iot_card-物联网卡 device-设备" json:"asset_type"`
|
||
// AssetID 资产ID,取自使用记录的绑定资产。
|
||
AssetID uint `gorm:"column:asset_id;type:bigint;not null;comment:资产ID" json:"asset_id"`
|
||
// AssetIdentifierSnapshot 资产标识快照。
|
||
AssetIdentifierSnapshot string `gorm:"column:asset_identifier_snapshot;type:varchar(100);not null;default:'';comment:资产标识快照" json:"asset_identifier_snapshot"`
|
||
// CardIdentifierSnapshot 卡标识快照。
|
||
CardIdentifierSnapshot string `gorm:"column:card_identifier_snapshot;type:varchar(100);not null;default:'';comment:卡标识快照" json:"card_identifier_snapshot"`
|
||
// CounterpartIdentifierSnapshot 对应标识符快照(卡→当前设备标识,设备→当前卡标识)。
|
||
CounterpartIdentifierSnapshot string `gorm:"column:counterpart_identifier_snapshot;type:varchar(100);not null;default:'';comment:对应标识符快照" json:"counterpart_identifier_snapshot"`
|
||
// DeviceTypeSnapshot 设备类型快照。
|
||
DeviceTypeSnapshot string `gorm:"column:device_type_snapshot;type:varchar(50);not null;default:'';comment:设备类型快照" json:"device_type_snapshot"`
|
||
// DeviceModelSnapshot 设备型号快照。
|
||
DeviceModelSnapshot string `gorm:"column:device_model_snapshot;type:varchar(100);not null;default:'';comment:设备型号快照" json:"device_model_snapshot"`
|
||
// PackageNameSnapshot 套餐名称快照。
|
||
PackageNameSnapshot string `gorm:"column:package_name_snapshot;type:varchar(255);not null;default:'';comment:套餐名称快照" json:"package_name_snapshot"`
|
||
// UsedMBSnapshot 触发时该资产全部当前有效套餐的真已用量汇总(MB)。
|
||
UsedMBSnapshot int64 `gorm:"column:used_mb_snapshot;type:bigint;not null;default:0;comment:真已用量汇总快照(MB)" json:"used_mb_snapshot"`
|
||
// LimitMBSnapshot 触发时该资产全部当前有效套餐的真总量快照汇总(MB)。
|
||
LimitMBSnapshot int64 `gorm:"column:limit_mb_snapshot;type:bigint;not null;comment:真总量快照汇总(MB)" json:"limit_mb_snapshot"`
|
||
// UsagePercentSnapshot 汇总比例快照,单位百分比。
|
||
UsagePercentSnapshot float64 `gorm:"column:usage_percent_snapshot;type:numeric(9,2);not null;default:0;comment:汇总比例快照(%)" json:"usage_percent_snapshot"`
|
||
// ThresholdPercentSnapshot 触发阈值快照,与使用记录组成唯一键。
|
||
ThresholdPercentSnapshot float64 `gorm:"column:threshold_percent_snapshot;type:numeric(5,2);not null;uniqueIndex:uq_package_traffic_alert_usage_threshold,priority:2;comment:触发阈值快照(%)" json:"threshold_percent_snapshot"`
|
||
// ExpiresAtSnapshot 主套餐使用记录到期时间快照;为空表示无法推算剩余天数。
|
||
ExpiresAtSnapshot *time.Time `gorm:"column:expires_at_snapshot;type:timestamptz;comment:主套餐到期时间快照" json:"expires_at_snapshot,omitempty"`
|
||
// TriggeredAt 触发时间。
|
||
TriggeredAt time.Time `gorm:"column:triggered_at;type:timestamptz;not null;comment:触发时间" json:"triggered_at"`
|
||
// ShopIDSnapshot 触发时资产所属店铺ID快照。
|
||
ShopIDSnapshot uint `gorm:"column:shop_id_snapshot;type:bigint;not null;default:0;comment:触发时所属店铺ID快照" json:"shop_id_snapshot"`
|
||
// ShopNameSnapshot 触发时店铺名称快照。
|
||
ShopNameSnapshot string `gorm:"column:shop_name_snapshot;type:varchar(100);not null;default:'';comment:触发时店铺名称快照" json:"shop_name_snapshot"`
|
||
// BusinessOwnerAccountIDSnapshot 触发时店铺业务员账号ID快照。
|
||
BusinessOwnerAccountIDSnapshot *uint `gorm:"column:business_owner_account_id_snapshot;type:bigint;comment:触发时业务员账号ID快照" json:"business_owner_account_id_snapshot,omitempty"`
|
||
// BusinessOwnerNameSnapshot 触发时业务员账号名快照。
|
||
BusinessOwnerNameSnapshot string `gorm:"column:business_owner_name_snapshot;type:varchar(64);not null;default:'';comment:触发时业务员名称快照" json:"business_owner_name_snapshot"`
|
||
// NotificationEventID 可靠通知事件ID;无有效业务员或写入失败前保持为空。
|
||
NotificationEventID string `gorm:"column:notification_event_id;type:varchar(64);not null;default:'';comment:可靠通知事件ID" json:"notification_event_id"`
|
||
// CreatedAt 创建时间。
|
||
CreatedAt time.Time `gorm:"column:created_at;type:timestamptz;not null;autoCreateTime" json:"created_at"`
|
||
// UpdatedAt 最近更新时间;预警事实创建后不再改写。
|
||
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamptz;not null;autoUpdateTime" json:"updated_at"`
|
||
}
|
||
|
||
// TableName 返回套餐真流量达量预警表名。
|
||
func (PackageTrafficAlert) TableName() string {
|
||
return "tb_package_traffic_alert"
|
||
}
|