feat: 按运营商账户调度的后台接口与重算到期

- /polling-carrier-params 列表(含默认标记与消费能力)、详情、保存(执行上限不得大于订阅进程 max_in_flight 之和)、删除;/polling-check-scenes 列表与修改(检查类型、递增的确认延迟、冷却);/polling-failure-alerts 列表、按账户与错误类别汇总、详情、标记已处理;GET /iot-cards/:id/polling-state 单卡轮询状态;GET /polling-stats/carrier-queues 按账户队列与执行监控
- 读取仅超级管理员与平台账号,修改仅超级管理员(告警处理平台账号可用),均写统一审计;新增审计动作与资源
- carrier 模式下重算到期时间写入卡到期信息与账户队列,只提前不推后
This commit is contained in:
邹进
2026-10-25 18:56:32 +09:00
parent 0d966249b8
commit c741f1751d
14 changed files with 1190 additions and 7 deletions

View File

@@ -0,0 +1,195 @@
package admin
import (
"strings"
"github.com/go-playground/validator/v10"
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
pollingSvc "github.com/break/junhong_cmp_fiber/internal/service/polling"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/response"
)
// CarrierSchedulerHandler 按运营商账户调度的后台接口:调度参数、请求检查场景、失败告警、单卡轮询状态、按账户监控。
type CarrierSchedulerHandler struct {
service *pollingSvc.CarrierSchedulerService
validator *validator.Validate
}
// NewCarrierSchedulerHandler 创建按运营商账户调度 Handler。
func NewCarrierSchedulerHandler(service *pollingSvc.CarrierSchedulerService, validator *validator.Validate) *CarrierSchedulerHandler {
return &CarrierSchedulerHandler{service: service, validator: validator}
}
func (h *CarrierSchedulerHandler) validate(prefix string, req any) error {
if err := h.validator.Struct(req); err != nil {
return errors.New(errors.CodeInvalidParam, validationMessage(prefix, req, err))
}
return nil
}
// ListParams 查询运营商账户调度参数列表。GET /api/admin/polling-carrier-params
func (h *CarrierSchedulerHandler) ListParams(c *fiber.Ctx) error {
result, err := h.service.ListParams(c.UserContext())
if err != nil {
return err
}
return response.Success(c, result)
}
// GetParam 查询运营商账户调度参数。GET /api/admin/polling-carrier-params/:carrier_id
func (h *CarrierSchedulerHandler) GetParam(c *fiber.Ctx) error {
carrierID, err := rateLimitPathID(c, "carrier_id", "运营商账户 ID")
if err != nil {
return err
}
result, err := h.service.GetParam(c.UserContext(), carrierID)
if err != nil {
return err
}
return response.Success(c, result)
}
// SaveParam 保存运营商账户调度参数。PUT /api/admin/polling-carrier-params/:carrier_id
func (h *CarrierSchedulerHandler) SaveParam(c *fiber.Ctx) error {
var req dto.SaveCarrierPollingParamRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
carrierID, err := rateLimitPathID(c, "carrier_id", "运营商账户 ID")
if err != nil {
return err
}
req.CarrierID = carrierID
if err := h.validate("运营商账户调度参数不合法", &req); err != nil {
return err
}
result, err := h.service.SaveParam(c.UserContext(), &req)
if err != nil {
return err
}
return response.Success(c, result)
}
// DeleteParam 删除运营商账户调度参数(恢复全局默认)。DELETE /api/admin/polling-carrier-params/:carrier_id
func (h *CarrierSchedulerHandler) DeleteParam(c *fiber.Ctx) error {
carrierID, err := rateLimitPathID(c, "carrier_id", "运营商账户 ID")
if err != nil {
return err
}
if err := h.service.DeleteParam(c.UserContext(), carrierID); err != nil {
return err
}
return response.Success(c, nil)
}
// ListScenes 查询请求检查场景。GET /api/admin/polling-check-scenes
func (h *CarrierSchedulerHandler) ListScenes(c *fiber.Ctx) error {
result, err := h.service.ListScenes(c.UserContext())
if err != nil {
return err
}
return response.Success(c, result)
}
// UpdateScene 修改请求检查场景。PUT /api/admin/polling-check-scenes/:scene
func (h *CarrierSchedulerHandler) UpdateScene(c *fiber.Ctx) error {
var req dto.UpdatePollingCheckSceneRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
req.Scene = strings.TrimSpace(c.Params("scene"))
if req.Scene == "" {
return errors.New(errors.CodeInvalidParam, "无效的场景编码")
}
if err := h.validate("请求检查场景参数不合法", &req); err != nil {
return err
}
result, err := h.service.UpdateScene(c.UserContext(), &req)
if err != nil {
return err
}
return response.Success(c, result)
}
// ListAlerts 查询卡轮询失败告警列表。GET /api/admin/polling-failure-alerts
func (h *CarrierSchedulerHandler) ListAlerts(c *fiber.Ctx) error {
var req dto.PollingFailureAlertListRequest
if err := c.QueryParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
if err := h.validate("卡轮询失败告警查询参数不合法", &req); err != nil {
return err
}
result, err := h.service.ListAlerts(c.UserContext(), &req)
if err != nil {
return err
}
return response.Success(c, result)
}
// AlertSummary 未处理告警按运营商账户 × 错误类别汇总。GET /api/admin/polling-failure-alerts/summary
func (h *CarrierSchedulerHandler) AlertSummary(c *fiber.Ctx) error {
result, err := h.service.AlertSummary(c.UserContext())
if err != nil {
return err
}
return response.Success(c, result)
}
// GetAlert 查询卡轮询失败告警详情。GET /api/admin/polling-failure-alerts/:id
func (h *CarrierSchedulerHandler) GetAlert(c *fiber.Ctx) error {
id, err := rateLimitPathID(c, "id", "告警 ID")
if err != nil {
return err
}
result, err := h.service.GetAlert(c.UserContext(), id)
if err != nil {
return err
}
return response.Success(c, result)
}
// HandleAlert 标记卡轮询失败告警已处理。PUT /api/admin/polling-failure-alerts/:id/status
func (h *CarrierSchedulerHandler) HandleAlert(c *fiber.Ctx) error {
var req dto.HandlePollingFailureAlertRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
id, err := rateLimitPathID(c, "id", "告警 ID")
if err != nil {
return err
}
req.ID = id
if err := h.validate("卡轮询失败告警处理参数不合法", &req); err != nil {
return err
}
if err := h.service.HandleAlert(c.UserContext(), &req); err != nil {
return err
}
return response.Success(c, nil)
}
// CardState 查询单卡轮询状态。GET /api/admin/iot-cards/:id/polling-state
func (h *CarrierSchedulerHandler) CardState(c *fiber.Ctx) error {
id, err := rateLimitPathID(c, "id", "卡 ID")
if err != nil {
return err
}
result, err := h.service.CardState(c.UserContext(), id)
if err != nil {
return err
}
return response.Success(c, result)
}
// CarrierStats 按运营商账户的轮询队列与执行监控。GET /api/admin/polling-stats/carrier-queues
func (h *CarrierSchedulerHandler) CarrierStats(c *fiber.Ctx) error {
result, err := h.service.CarrierStats(c.UserContext())
if err != nil {
return err
}
return response.Success(c, result)
}