All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m57s
- 匹配预览 GET 只收 query iccid,POST 只收请求体,去掉 POST 文档中多余的 query 参数 - 预览草稿 overrides 改为独立结构,字段全部可选,最多 20 条 - clear_fields 用具名类型生成数组元素枚举;ordered_ids 说明须为正整数且不重复
289 lines
9.2 KiB
Go
289 lines
9.2 KiB
Go
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 {
|
||
var query dto.PollingConfigMatchPreviewQuery
|
||
if err := c.QueryParser(&query); err != nil {
|
||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||
}
|
||
req.ICCID = query.ICCID
|
||
}
|
||
if len(req.Overrides) > 20 {
|
||
return errors.New(errors.CodeInvalidParam, "匹配预览参数不合法:未保存修改最多 20 条")
|
||
}
|
||
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)
|
||
}
|