新增 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。
84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
package exporter
|
|
|
|
import (
|
|
"sort"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
)
|
|
|
|
// Registry 导出数据源注册中心。
|
|
type Registry struct {
|
|
sources map[string]DataSource
|
|
}
|
|
|
|
// NewRegistry 创建导出数据源注册中心。
|
|
func NewRegistry(sources ...DataSource) *Registry {
|
|
m := make(map[string]DataSource, len(sources))
|
|
for _, source := range sources {
|
|
if source == nil {
|
|
continue
|
|
}
|
|
m[source.Scene()] = source
|
|
}
|
|
return &Registry{sources: m}
|
|
}
|
|
|
|
// NewDefaultRegistry 创建默认导出数据源注册中心。
|
|
func NewDefaultRegistry(db *gorm.DB) *Registry {
|
|
return NewRegistry(
|
|
NewDeviceDataSource(db),
|
|
NewIotCardDataSource(db),
|
|
NewOrderDataSource(db),
|
|
NewPackageDataSource(db),
|
|
NewAgentWalletTransactionDataSource(db),
|
|
NewAgentRechargeDataSource(db),
|
|
NewRefundDataSource(db),
|
|
NewExchangeDataSource(db),
|
|
NewCommissionRecordDataSource(db),
|
|
NewPackageTrafficAlertDataSource(db),
|
|
)
|
|
}
|
|
|
|
// Get 获取指定场景数据源。
|
|
func (r *Registry) Get(scene string) (DataSource, bool) {
|
|
source, ok := r.sources[scene]
|
|
return source, ok
|
|
}
|
|
|
|
// IsSupported 判断场景是否支持。
|
|
func (r *Registry) IsSupported(scene string) bool {
|
|
_, ok := r.sources[scene]
|
|
return ok
|
|
}
|
|
|
|
// Scenes 返回当前支持的场景列表。
|
|
func (r *Registry) Scenes() []string {
|
|
result := make([]string, 0, len(r.sources))
|
|
for scene := range r.sources {
|
|
result = append(result, scene)
|
|
}
|
|
sort.Strings(result)
|
|
return result
|
|
}
|
|
|
|
// IsSupportedScene 判断是否为受支持的场景。
|
|
func IsSupportedScene(scene string) bool {
|
|
switch scene {
|
|
case constants.ExportTaskSceneDevice,
|
|
constants.ExportTaskSceneIotCard,
|
|
constants.ExportTaskSceneOrder,
|
|
constants.ExportTaskScenePackage,
|
|
constants.ExportTaskSceneAgentWalletTransaction,
|
|
constants.ExportTaskSceneAgentRecharge,
|
|
constants.ExportTaskSceneRefund,
|
|
constants.ExportTaskSceneExchange,
|
|
constants.ExportTaskSceneCommissionRecord,
|
|
constants.ExportTaskScenePackageTrafficAlert:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|