package admin import ( "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v2" packagesilenceapp "github.com/break/junhong_cmp_fiber/internal/application/packagesilence" "github.com/break/junhong_cmp_fiber/internal/model/dto" packagesilencequery "github.com/break/junhong_cmp_fiber/internal/query/packagesilence" "github.com/break/junhong_cmp_fiber/pkg/errors" "github.com/break/junhong_cmp_fiber/pkg/response" ) // PackageSilenceHandler 后台沉默期:总开关、延期政策、延期资格、延期订单、线下登记、特殊延期、批次、异常、流水与首次购买套餐记录。 // Handler 只做绑定与参数校验,权限点、数据范围、金额与状态由用例判断。 type PackageSilenceHandler struct { switches *packagesilenceapp.SwitchService policies *packagesilenceapp.PolicyService extensions *packagesilenceapp.ExtensionService query *packagesilencequery.Query validator *validator.Validate } // NewPackageSilenceHandler 创建后台沉默期 Handler。 func NewPackageSilenceHandler( switches *packagesilenceapp.SwitchService, policies *packagesilenceapp.PolicyService, extensions *packagesilenceapp.ExtensionService, query *packagesilencequery.Query, validator *validator.Validate, ) *PackageSilenceHandler { return &PackageSilenceHandler{switches: switches, policies: policies, extensions: extensions, query: query, validator: validator} } func (h *PackageSilenceHandler) bindQuery(c *fiber.Ctx, prefix string, req any) error { if err := c.QueryParser(req); err != nil { return errors.New(errors.CodeInvalidParam, "请求参数解析失败") } return h.validate(prefix, req) } func (h *PackageSilenceHandler) bindBody(c *fiber.Ctx, prefix string, req any) error { if err := c.BodyParser(req); err != nil { return errors.New(errors.CodeInvalidParam, "请求参数解析失败") } return h.validate(prefix, req) } func (h *PackageSilenceHandler) validate(prefix string, req any) error { if h.validator == nil { return nil } if err := h.validator.Struct(req); err != nil { return errors.New(errors.CodeInvalidParam, validationMessage(prefix, req, err)) } return nil } func silencePathID(c *fiber.Ctx) (uint, error) { id, err := c.ParamsInt("id") if err != nil || id <= 0 { return 0, errors.New(errors.CodeInvalidParam, "ID 无效") } return uint(id), nil } // GetSwitch 查询沉默期总开关与打开前检查。GET /api/admin/package-silence/switch func (h *PackageSilenceHandler) GetSwitch(c *fiber.Ctx) error { result, err := h.switches.Status(c.UserContext()) if err != nil { return err } return response.Success(c, result) } // UpdateSwitch 切换沉默期总开关(仅超级管理员)。PUT /api/admin/package-silence/switch func (h *PackageSilenceHandler) UpdateSwitch(c *fiber.Ctx) error { var req dto.SilenceSwitchRequest if err := h.bindBody(c, "沉默期总开关参数不合法", &req); err != nil { return err } result, err := h.switches.Toggle(c.UserContext(), *req.Enabled) if err != nil { return err } return response.Success(c, result) } // ListPolicies 延期政策列表。GET /api/admin/package-silence/policies func (h *PackageSilenceHandler) ListPolicies(c *fiber.Ctx) error { var req dto.SilencePolicyListRequest if err := h.bindQuery(c, "延期政策查询参数不合法", &req); err != nil { return err } items, total, err := h.policies.List(c.UserContext(), &req) if err != nil { return err } page, pageSize := req.Page, req.PageSize if page < 1 { page = 1 } if pageSize < 1 { pageSize = 20 } return response.SuccessWithPagination(c, items, total, page, pageSize) } // GetPolicy 延期政策详情。GET /api/admin/package-silence/policies/:id func (h *PackageSilenceHandler) GetPolicy(c *fiber.Ctx) error { id, err := silencePathID(c) if err != nil { return err } result, err := h.policies.Get(c.UserContext(), id) if err != nil { return err } return response.Success(c, result) } // CreatePolicy 新增延期政策。POST /api/admin/package-silence/policies func (h *PackageSilenceHandler) CreatePolicy(c *fiber.Ctx) error { var req dto.SilencePolicyRequest if err := h.bindBody(c, "延期政策参数不合法", &req); err != nil { return err } result, err := h.policies.Create(c.UserContext(), &req) if err != nil { return err } return response.Success(c, result) } // UpdatePolicy 编辑延期政策。PUT /api/admin/package-silence/policies/:id func (h *PackageSilenceHandler) UpdatePolicy(c *fiber.Ctx) error { id, err := silencePathID(c) if err != nil { return err } var req dto.SilencePolicyRequest if err := h.bindBody(c, "延期政策参数不合法", &req); err != nil { return err } result, err := h.policies.Update(c.UserContext(), id, &req) if err != nil { return err } return response.Success(c, result) } // UpdatePolicyStatus 启停延期政策。PUT /api/admin/package-silence/policies/:id/status func (h *PackageSilenceHandler) UpdatePolicyStatus(c *fiber.Ctx) error { id, err := silencePathID(c) if err != nil { return err } var req dto.SilencePolicyStatusRequest if err := h.bindBody(c, "延期政策状态参数不合法", &req); err != nil { return err } result, err := h.policies.SetStatus(c.UserContext(), id, *req.Status) if err != nil { return err } return response.Success(c, result) } // MatchPolicy 查询套餐当前匹配的延期政策。GET /api/admin/package-silence/policies/match func (h *PackageSilenceHandler) MatchPolicy(c *fiber.Ctx) error { var req dto.SilencePolicyMatchRequest if err := h.bindQuery(c, "政策匹配查询参数不合法", &req); err != nil { return err } result, err := h.policies.MatchForPackage(c.UserContext(), req.PackageID) if err != nil { return err } return response.Success(c, result) } // Eligibility 延期资格。GET /api/admin/package-silence/eligibility func (h *PackageSilenceHandler) Eligibility(c *fiber.Ctx) error { var req dto.SilenceEligibilityRequest if err := h.bindQuery(c, "延期资格查询参数不合法", &req); err != nil { return err } result, err := h.extensions.Eligibility(c.UserContext(), req.PackageUsageID, packagesilenceapp.Scope{}) if err != nil { return err } return response.Success(c, result) } // Quote 按天数试算付费延期。GET /api/admin/package-silence/quote func (h *PackageSilenceHandler) Quote(c *fiber.Ctx) error { var req dto.SilenceQuoteRequest if err := h.bindQuery(c, "延期试算参数不合法", &req); err != nil { return err } result, err := h.extensions.Quote(c.UserContext(), req.PackageUsageID, req.Days, packagesilenceapp.Scope{}) if err != nil { return err } return response.Success(c, result) } // CreateQRCodeOrder 运营创建在线延期订单并生成支付二维码。POST /api/admin/package-silence/orders/qrcode func (h *PackageSilenceHandler) CreateQRCodeOrder(c *fiber.Ctx) error { var req dto.SilenceOnlineOrderRequest if err := h.bindBody(c, "延期下单参数不合法", &req); err != nil { return err } result, err := h.extensions.CreateOnlineOrder(c.UserContext(), packagesilenceapp.OnlineOrderCommand{ Request: req, Scope: packagesilenceapp.Scope{}, PayerClientIP: c.IP(), }) if err != nil { return err } return response.Success(c, result) } // RegisterOffline 登记线下付费延期。POST /api/admin/package-silence/orders/offline func (h *PackageSilenceHandler) RegisterOffline(c *fiber.Ctx) error { var req dto.SilenceOfflineOrderRequest if err := h.bindBody(c, "线下付费延期参数不合法", &req); err != nil { return err } result, err := h.extensions.RegisterOffline(c.UserContext(), req) if err != nil { return err } return response.Success(c, result) } // ListOrders 延期订单列表。GET /api/admin/package-silence/orders func (h *PackageSilenceHandler) ListOrders(c *fiber.Ctx) error { var req dto.SilenceOrderListRequest if err := h.bindQuery(c, "延期订单查询参数不合法", &req); err != nil { return err } result, err := h.query.ListOrders(c.UserContext(), packagesilencequery.OrderFilter{Request: req}) if err != nil { return err } return response.Success(c, result) } // GetOrder 延期订单详情。GET /api/admin/package-silence/orders/:id func (h *PackageSilenceHandler) GetOrder(c *fiber.Ctx) error { id, err := silencePathID(c) if err != nil { return err } result, err := h.query.GetOrder(c.UserContext(), id, 0) if err != nil { return err } return response.Success(c, result) } // SubmitSpecial 提交特殊延期(单个 / 批量)。POST /api/admin/package-silence/special func (h *PackageSilenceHandler) SubmitSpecial(c *fiber.Ctx) error { var req dto.SilenceSpecialRequest if err := h.bindBody(c, "特殊延期参数不合法", &req); err != nil { return err } result, err := h.extensions.SubmitSpecial(c.UserContext(), req) if err != nil { return err } return response.Success(c, result) } // ListBatches 延期批次列表。GET /api/admin/package-silence/batches func (h *PackageSilenceHandler) ListBatches(c *fiber.Ctx) error { var req dto.SilenceBatchListRequest if err := h.bindQuery(c, "延期批次查询参数不合法", &req); err != nil { return err } result, err := h.query.ListBatches(c.UserContext(), req) if err != nil { return err } return response.Success(c, result) } // GetBatch 延期批次详情(含明细)。GET /api/admin/package-silence/batches/:id func (h *PackageSilenceHandler) GetBatch(c *fiber.Ctx) error { id, err := silencePathID(c) if err != nil { return err } result, err := h.extensions.BatchDetail(c.UserContext(), id) if err != nil { return err } return response.Success(c, result) } // HandleException 异常明细重试 / 关闭。POST /api/admin/package-silence/extensions/:id/handle func (h *PackageSilenceHandler) HandleException(c *fiber.Ctx) error { id, err := silencePathID(c) if err != nil { return err } var req dto.SilenceExceptionHandleRequest if err := h.bindBody(c, "异常处理参数不合法", &req); err != nil { return err } result, err := h.extensions.HandleException(c.UserContext(), id, req) if err != nil { return err } return response.Success(c, result) } // ListRecords 套餐沉默期流水。GET /api/admin/package-silence/records func (h *PackageSilenceHandler) ListRecords(c *fiber.Ctx) error { var req dto.SilenceRecordListRequest if err := h.bindQuery(c, "沉默期流水查询参数不合法", &req); err != nil { return err } result, err := h.extensions.Records(c.UserContext(), req.PackageUsageID, packagesilenceapp.Scope{}) if err != nil { return err } return response.Success(c, result) } // ListUsages 即将过期 / 已过期套餐。GET /api/admin/package-silence/usages func (h *PackageSilenceHandler) ListUsages(c *fiber.Ctx) error { var req dto.SilenceUsageListRequest if err := h.bindQuery(c, "沉默期套餐查询参数不合法", &req); err != nil { return err } result, err := h.query.ListUsages(c.UserContext(), req) if err != nil { return err } return response.Success(c, result) } // ListFirstPurchaseRecords 资产各世代首次购买套餐记录。GET /api/admin/assets/:asset_type/:id/first-purchase-records func (h *PackageSilenceHandler) ListFirstPurchaseRecords(c *fiber.Ctx) error { id, err := silencePathID(c) if err != nil { return err } assetType := c.Params("asset_type") if assetType != "card" && assetType != "iot_card" && assetType != "device" { return errors.New(errors.CodeInvalidParam, "资产类型仅支持 card 或 device") } result, err := h.query.ListFirstPurchaseRecords(c.UserContext(), assetType, id) if err != nil { return err } return response.Success(c, result) }