5.6 KiB
5.6 KiB
需求10:限速规则
背景
Gateway 已有 SetSpeedLimit 接口,支持卡和设备:
// internal/gateway/device.go
func (c *Client) SetSpeedLimit(ctx context.Context, req *SpeedLimitReq) error
// internal/gateway/models.go
type SpeedLimitReq struct {
CardNo string `json:"cardNo,omitempty"` // 卡(与 DeviceID 二选一)
DeviceID string `json:"deviceId,omitempty"` // 设备(与 CardNo 二选一)
SpeedLimit int `json:"speedLimit"` // 限速值(KB/s),0=不限速
Extend string `json:"extend,omitempty"`
}
"根据不同运营商限速规则,基于套餐流量设置不同的卡/设备的限速规则"
设计思路:限速规则配置在套餐上(不同运营商、不同流量档位对应不同套餐,套餐本身就是差异载体)。套餐激活时自动调用 Gateway 设置限速。
数据库变更
-- 套餐表增加限速字段
ALTER TABLE tb_package
ADD COLUMN speed_limit_kbps INT NOT NULL DEFAULT 0
COMMENT '限速值(KB/s),0=不限速';
Model 变更
// internal/model/package.go
type Package struct {
// ...原有字段...
SpeedLimitKbps int `gorm:"column:speed_limit_kbps;type:int;not null;default:0;comment:限速值(KB/s),0=不限速" json:"speed_limit_kbps"`
}
后端实现
1. 套餐激活时设置限速
在 internal/service/package/activation_service.go 中,套餐激活(ActivatedAt 赋值)时调用限速:
// activatePackageUsage 套餐激活核心逻辑(已有函数,追加限速调用)
func (s *ActivationService) activatePackageUsage(ctx context.Context, usage *model.PackageUsage, pkg *model.Package) error {
// ...现有激活逻辑...
// 套餐有限速配置时,调用 Gateway 设置
if pkg.SpeedLimitKbps > 0 {
if err := s.applySpeedLimit(ctx, usage, pkg.SpeedLimitKbps); err != nil {
// 限速失败不阻断套餐激活,记录错误日志
s.logger.Error("设置限速失败", zap.Error(err),
zap.Uint("package_usage_id", usage.ID),
zap.Int("speed_limit", pkg.SpeedLimitKbps))
}
}
return nil
}
// applySpeedLimit 调用 Gateway 设置限速
func (s *ActivationService) applySpeedLimit(ctx context.Context, usage *model.PackageUsage, speedKbps int) error {
req := &gateway.SpeedLimitReq{SpeedLimit: speedKbps}
switch usage.UsageType {
case constants.PackageUsageTypeSingleCard: // "single_card",定义在 pkg/constants/iot.go
// 查卡的 ICCID
card, err := s.iotCardStore.GetByID(ctx, usage.IotCardID)
if err != nil { return err }
req.CardNo = card.ICCID
case constants.PackageUsageTypeDevice: // "device",定义在 pkg/constants/iot.go
// 查设备的 IMEI
device, err := s.deviceStore.GetByID(ctx, usage.DeviceID)
if err != nil { return err }
req.DeviceID = device.IMEI
}
return s.gatewayClient.SetSpeedLimit(ctx, req)
}
2. 套餐到期/失效时取消限速
当套餐状态变为 已过期(3) 或 已失效(4) 时,重置限速为 0(不限速)。
在套餐过期处理任务中追加:
// 套餐过期时取消限速(SpeedLimit=0 表示不限速)
if expiredPkg.SpeedLimitKbps > 0 {
s.applySpeedLimit(ctx, usage, 0) // 0 = 不限速
}
注意:如果有续费的排队套餐立即生效,应以新套餐的限速为准,而不是先取消再设置。
3. 手动操作限速(后台管理)
POST /admin/iot-cards/{id}/speed-limit
POST /admin/devices/{id}/speed-limit
请求体:
type SetSpeedLimitRequest struct {
SpeedLimitKbps int `json:"speed_limit_kbps" validate:"min=0" description:"限速值(KB/s),0=取消限速"`
}
直接调 Gateway,不更新套餐配置(临时操作)。
API 变更(套餐管理)
创建/更新套餐新增字段
POST /admin/packages
PUT /admin/packages/{id}
新增参数:
SpeedLimitKbps int `json:"speed_limit_kbps" validate:"min=0" description:"限速值(KB/s),0=不限速"`
套餐列表/详情响应新增字段
type PackageResponse struct {
// ...原有字段...
SpeedLimitKbps int `json:"speed_limit_kbps" description:"限速值(KB/s),0=不限速"`
SpeedLimitDesc string `json:"speed_limit_desc" description:"限速描述(如 '512 KB/s',0时为'不限速')"`
}
前端对接
页面:套餐创建/编辑
在"套餐配置"区域新增限速项:
限速配置:
限速值:[____] KB/s (0 或留空 = 不限速)
提示文案:留空或填 0 表示不限速;建议根据运营商规则填写
前端换算提示(可选):512 KB/s ≈ 4 Mbps
页面:套餐列表
新增"限速"列:
0→ 显示"不限速">0→ 显示"XXX KB/s"
页面:资产详情 > 操作区
新增"手动设置限速"按钮(仅当有生效套餐时显示):
弹框:
当前限速:xxx KB/s(来自套餐配置)
临时设置:[____] KB/s [0=取消限速]
[确认设置] → POST /admin/iot-cards/{id}/speed-limit
注意事项
- Gateway 调用失败不阻断业务:限速设置失败只记录日志,套餐仍然激活。
- 限速精度:Gateway
SpeedLimit单位是 KB/s,最小值为 1;填 0 表示不限速。 - 运营商差异:不同运营商通过创建不同套餐来体现限速差异,不需要在套餐外额外维护运营商-限速映射表。
- 续费场景:新套餐生效时重新设置限速,以新套餐的限速值为准。