Files
junhong_cmp_fiber/internal/handler/admin/polling_config.go
邹进 98017ac053
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m37s
feat: 分层轮询、重置日前加密与激活前流量结算
- 轮询配置新增套餐状态、资产状态、重置日前窗口与窗口内流量间隔(迁移 248),间隔三态:正数按间隔、0 不检查、空继承
- 配置按 priority, id 排序合并;在库与已销售无套餐未匹配时告警不入队
- 新增优先级整体重排、匹配预览、立即重算到期时间(异步只提前)、分层统计与重置日前加密统计接口
- 已切换日快照计量的卡流量按观测时间归属,激活前用量只记已结算
- 订单购买与实名激活补齐资产级激活锁,激活前对已切换卡结算一次流量,失败只告警不阻塞,结算不触发通道阈值判定
2026-10-24 17:06:38 +09:00

282 lines
8.9 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 admin
import (
"strconv"
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
pollingService "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"
)
// PollingConfigHandler 轮询配置 Handler
type PollingConfigHandler struct {
service *pollingService.ConfigService
}
// NewPollingConfigHandler 创建轮询配置 Handler 实例
func NewPollingConfigHandler(service *pollingService.ConfigService) *PollingConfigHandler {
return &PollingConfigHandler{service: service}
}
// List 获取轮询配置列表
// @Summary 获取轮询配置列表
// @Description 获取轮询配置列表,支持分页和筛选
// @Tags 轮询配置管理
// @Accept json
// @Produce json
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Param status query int false "状态 (1:启用, 0:禁用)"
// @Param card_condition query string false "卡状态条件"
// @Param card_category query string false "卡业务类型"
// @Param carrier_id query int false "运营商ID"
// @Param config_name query string false "配置名称"
// @Success 200 {object} response.Response{data=dto.PollingConfigPageResult}
// @Router /api/admin/polling-configs [get]
func (h *PollingConfigHandler) List(c *fiber.Ctx) error {
var req dto.PollingConfigListRequest
if err := c.QueryParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam)
}
configs, total, err := h.service.List(c.UserContext(), &req)
if err != nil {
return err
}
return response.SuccessWithPagination(c, configs, total, req.Page, req.PageSize)
}
// Create 创建轮询配置
// @Summary 创建轮询配置
// @Description 创建新的轮询配置
// @Tags 轮询配置管理
// @Accept json
// @Produce json
// @Param body body dto.CreatePollingConfigRequest true "创建轮询配置请求"
// @Success 200 {object} response.Response{data=dto.PollingConfigResponse}
// @Router /api/admin/polling-configs [post]
func (h *PollingConfigHandler) Create(c *fiber.Ctx) error {
var req dto.CreatePollingConfigRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam)
}
config, err := h.service.Create(c.UserContext(), &req)
if err != nil {
return err
}
return response.Success(c, config)
}
// Get 获取轮询配置详情
// @Summary 获取轮询配置详情
// @Description 根据 ID 获取轮询配置详情
// @Tags 轮询配置管理
// @Accept json
// @Produce json
// @Param id path int true "配置ID"
// @Success 200 {object} response.Response{data=dto.PollingConfigResponse}
// @Router /api/admin/polling-configs/{id} [get]
func (h *PollingConfigHandler) Get(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的配置 ID")
}
config, err := h.service.Get(c.UserContext(), uint(id))
if err != nil {
return err
}
return response.Success(c, config)
}
// Update 更新轮询配置
// @Summary 更新轮询配置
// @Description 根据 ID 更新轮询配置
// @Tags 轮询配置管理
// @Accept json
// @Produce json
// @Param id path int true "配置ID"
// @Param body body dto.UpdatePollingConfigRequest true "更新轮询配置请求"
// @Success 200 {object} response.Response{data=dto.PollingConfigResponse}
// @Router /api/admin/polling-configs/{id} [put]
func (h *PollingConfigHandler) Update(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的配置 ID")
}
var req dto.UpdatePollingConfigRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam)
}
config, err := h.service.Update(c.UserContext(), uint(id), &req)
if err != nil {
return err
}
return response.Success(c, config)
}
// Delete 删除轮询配置
// @Summary 删除轮询配置
// @Description 根据 ID 删除轮询配置
// @Tags 轮询配置管理
// @Accept json
// @Produce json
// @Param id path int true "配置ID"
// @Success 200 {object} response.Response
// @Router /api/admin/polling-configs/{id} [delete]
func (h *PollingConfigHandler) Delete(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的配置 ID")
}
if err := h.service.Delete(c.UserContext(), uint(id)); err != nil {
return err
}
return response.Success(c, nil)
}
// UpdateStatus 更新轮询配置状态
// @Summary 更新轮询配置状态
// @Description 启用或禁用轮询配置
// @Tags 轮询配置管理
// @Accept json
// @Produce json
// @Param id path int true "配置ID"
// @Param body body dto.UpdatePollingConfigStatusRequest true "更新状态请求"
// @Success 200 {object} response.Response
// @Router /api/admin/polling-configs/{id}/status [put]
func (h *PollingConfigHandler) UpdateStatus(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil {
return errors.New(errors.CodeInvalidParam, "无效的配置 ID")
}
var req dto.UpdatePollingConfigStatusRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam)
}
if err := h.service.UpdateStatus(c.UserContext(), uint(id), req.Status); err != nil {
return err
}
return response.Success(c, nil)
}
// ListEnabled 获取所有启用的配置
// @Summary 获取所有启用的配置
// @Description 获取所有启用状态的轮询配置,按优先级排序
// @Tags 轮询配置管理
// @Accept json
// @Produce json
// @Success 200 {object} response.Response{data=[]dto.PollingConfigResponse}
// @Router /api/admin/polling-configs/enabled [get]
func (h *PollingConfigHandler) ListEnabled(c *fiber.Ctx) error {
configs, err := h.service.ListEnabled(c.UserContext())
if err != nil {
return err
}
return response.Success(c, configs)
}
// UpdatePriorities 按给定顺序整体调整轮询配置优先级(仅超级管理员)。
// PUT /api/admin/polling-configs/priorities
func (h *PollingConfigHandler) UpdatePriorities(c *fiber.Ctx) error {
var req dto.UpdatePollingConfigPrioritiesRequest
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
if len(req.OrderedIDs) == 0 {
return errors.New(errors.CodeInvalidParam, "轮询配置优先级参数不合法:配置 ID 列表不能为空")
}
if err := h.service.UpdatePriorities(c.UserContext(), &req); err != nil {
return err
}
return response.Success(c, nil)
}
// MatchPreview 预览一张卡的轮询配置匹配结果;GET 只按当前配置,POST 可带未保存修改,均不写数据。
// GET /api/admin/polling-configs/match-preview
// POST /api/admin/polling-configs/match-preview
func (h *PollingConfigHandler) MatchPreview(c *fiber.Ctx) error {
var req dto.PollingConfigMatchPreviewRequest
if c.Method() == fiber.MethodPost {
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
} else if err := c.QueryParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
if req.ICCID == "" {
return errors.New(errors.CodeInvalidParam, "匹配预览参数不合法:ICCID 不能为空")
}
result, err := h.service.MatchPreview(c.UserContext(), &req)
if err != nil {
return err
}
return response.Success(c, result)
}
// CreateRecalculateTask 创建"立即重算到期时间"异步任务(仅超级管理员)。
// POST /api/admin/polling-configs/recalculate-due
func (h *PollingConfigHandler) CreateRecalculateTask(c *fiber.Ctx) error {
var req dto.PollingRecalculateDueRequest
if len(c.Body()) > 0 {
if err := c.BodyParser(&req); err != nil {
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
}
}
result, err := h.service.CreateRecalculateTask(c.UserContext(), &req)
if err != nil {
return err
}
return response.Success(c, result)
}
// GetRecalculateTask 查询重算到期时间任务进度。
// GET /api/admin/polling-configs/recalculate-due/:task_id
func (h *PollingConfigHandler) GetRecalculateTask(c *fiber.Ctx) error {
taskID := c.Params("task_id")
if taskID == "" {
return errors.New(errors.CodeInvalidParam, "重算任务 ID 不能为空")
}
result, err := h.service.GetRecalculateTask(c.UserContext(), taskID)
if err != nil {
return err
}
return response.Success(c, result)
}
// TierStats 查询分层轮询统计(结果缓存 5 分钟)。
// GET /api/admin/polling-stats/tiers
func (h *PollingConfigHandler) TierStats(c *fiber.Ctx) error {
result, err := h.service.TierStats(c.UserContext())
if err != nil {
return err
}
return response.Success(c, result)
}
// PreResetStats 查询重置日前加密效果统计。
// GET /api/admin/polling-stats/pre-reset
func (h *PollingConfigHandler) PreResetStats(c *fiber.Ctx) error {
result, err := h.service.PreResetStats(c.UserContext())
if err != nil {
return err
}
return response.Success(c, result)
}