package httpapi import ( "encoding/json" "errors" "net/http" "strings" "github.com/easyai/easyai-ai-gateway/apps/api/internal/store" ) // listPricingRuleSets godoc // @Summary 列出定价规则集 // @Description 管理端返回可分配给平台、模型、租户或用户组的定价规则集。 // @Tags pricing // @Produce json // @Security BearerAuth // @Success 200 {object} PricingRuleSetListResponse // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/pricing/rule-sets [get] func (s *Server) listPricingRuleSets(w http.ResponseWriter, r *http.Request) { items, err := s.store.ListPricingRuleSets(r.Context()) if err != nil { s.logger.Error("list pricing rule sets failed", "error", err) writeError(w, http.StatusInternalServerError, "list pricing rule sets failed") return } writeJSON(w, http.StatusOK, map[string]any{"items": items}) } // createPricingRuleSet godoc // @Summary 创建定价规则集 // @Description 管理端创建定价规则集,ruleSetKey、name 和至少一条 rule 必填。 // @Tags pricing // @Accept json // @Produce json // @Security BearerAuth // @Param input body store.PricingRuleSetInput true "定价规则集请求" // @Success 201 {object} store.PricingRuleSet // @Failure 400 {object} ErrorEnvelope // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 409 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/pricing/rule-sets [post] func (s *Server) createPricingRuleSet(w http.ResponseWriter, r *http.Request) { var input store.PricingRuleSetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { writeError(w, http.StatusBadRequest, "invalid json body") return } if !validPricingRuleSetInput(input) { writeError(w, http.StatusBadRequest, "ruleSetKey, name and at least one rule are required") return } item, err := s.store.CreatePricingRuleSet(r.Context(), input) if err != nil { if store.IsUniqueViolation(err) { writeError(w, http.StatusConflict, "pricing rule set key already exists") return } s.logger.Error("create pricing rule set failed", "error", err) writeError(w, http.StatusInternalServerError, "create pricing rule set failed") return } writeJSON(w, http.StatusCreated, item) } // updatePricingRuleSet godoc // @Summary 更新定价规则集 // @Description 管理端更新定价规则集及其规则列表。 // @Tags pricing // @Accept json // @Produce json // @Security BearerAuth // @Param ruleSetID path string true "定价规则集 ID" // @Param input body store.PricingRuleSetInput true "定价规则集请求" // @Success 200 {object} store.PricingRuleSet // @Failure 400 {object} ErrorEnvelope // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 404 {object} ErrorEnvelope // @Failure 409 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/pricing/rule-sets/{ruleSetID} [patch] func (s *Server) updatePricingRuleSet(w http.ResponseWriter, r *http.Request) { var input store.PricingRuleSetInput if err := json.NewDecoder(r.Body).Decode(&input); err != nil { writeError(w, http.StatusBadRequest, "invalid json body") return } if !validPricingRuleSetInput(input) { writeError(w, http.StatusBadRequest, "ruleSetKey, name and at least one rule are required") return } item, err := s.store.UpdatePricingRuleSet(r.Context(), r.PathValue("ruleSetID"), input) if err != nil { if store.IsNotFound(err) { writeError(w, http.StatusNotFound, "pricing rule set not found") return } if store.IsUniqueViolation(err) { writeError(w, http.StatusConflict, "pricing rule set key already exists") return } s.logger.Error("update pricing rule set failed", "error", err) writeError(w, http.StatusInternalServerError, "update pricing rule set failed") return } writeJSON(w, http.StatusOK, item) } // deletePricingRuleSet godoc // @Summary 删除定价规则集 // @Description 管理端删除非默认定价规则集;默认规则集受保护。 // @Tags pricing // @Produce json // @Security BearerAuth // @Param ruleSetID path string true "定价规则集 ID" // @Success 204 "No Content" // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 404 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/admin/pricing/rule-sets/{ruleSetID} [delete] func (s *Server) deletePricingRuleSet(w http.ResponseWriter, r *http.Request) { if err := s.store.DeletePricingRuleSet(r.Context(), r.PathValue("ruleSetID")); err != nil { if store.IsNotFound(err) { writeError(w, http.StatusNotFound, "pricing rule set not found") return } if errors.Is(err, store.ErrProtectedDefault) { writeError(w, http.StatusForbidden, "default pricing rule set cannot be deleted") return } s.logger.Error("delete pricing rule set failed", "error", err) writeError(w, http.StatusInternalServerError, "delete pricing rule set failed") return } w.WriteHeader(http.StatusNoContent) } func validPricingRuleSetInput(input store.PricingRuleSetInput) bool { if strings.TrimSpace(input.RuleSetKey) == "" || strings.TrimSpace(input.Name) == "" || len(input.Rules) == 0 { return false } for _, rule := range input.Rules { if strings.TrimSpace(rule.ResourceType) == "" || strings.TrimSpace(rule.Unit) == "" { return false } } return true }