package api import ( "errors" "net/http" "strconv" "strings" "github.com/gin-gonic/gin" "level_go/internal/model" "level_go/internal/service" ) type LimitBoardHandler struct { Service *service.LimitBoardService } func NewLimitBoardHandler(s *service.LimitBoardService) *LimitBoardHandler { return &LimitBoardHandler{Service: s} } func (h *LimitBoardHandler) GetOverview(c *gin.Context) { var req model.LimitBoardRequest if err := c.ShouldBindQuery(&req); err != nil || req.TradeDate == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "trade_date 参数不能为空"}) return } resp, err := h.Service.GetLimitBoardOverview(req.TradeDate) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, resp) } func (h *LimitBoardHandler) GetOpenLowerGroups(c *gin.Context) { var req model.LimitBoardRequest if err := c.ShouldBindQuery(&req); err != nil || req.TradeDate == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "trade_date 参数不能为空"}) return } resp, err := h.Service.GetLimitOpenCompareGroups(req.TradeDate) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, resp) } func (h *LimitBoardHandler) GetBreakNextPerformance(c *gin.Context) { req, err := parseLimitBreakNextPerformanceRequest(c, true) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } resp, err := h.Service.GetLimitBreakNextPerformance(req) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, resp) } func parseLimitBreakNextPerformanceRequest(c *gin.Context, includePagination bool) (model.LimitBreakNextPerformanceRequest, error) { req := model.LimitBreakNextPerformanceRequest{ TradeStartDate: strings.TrimSpace(c.DefaultQuery("tradeStartDate", c.Query("start_date"))), TradeEndDate: strings.TrimSpace(c.DefaultQuery("tradeEndDate", c.Query("end_date"))), Page: 1, PageSize: 20, } if req.TradeStartDate == "" { return req, errors.New("tradeStartDate 参数不能为空") } if req.TradeEndDate == "" { return req, errors.New("tradeEndDate 参数不能为空") } if err := validateSecondProfitDateRange(req.TradeStartDate, req.TradeEndDate); err != nil { return req, err } if includePagination { pageText := strings.TrimSpace(c.DefaultQuery("page", "1")) page, err := strconv.Atoi(pageText) if err != nil || page <= 0 { return req, errors.New("page 必须为正整数") } req.Page = page pageSizeText := strings.TrimSpace(c.DefaultQuery("pageSize", "20")) pageSize, err := strconv.Atoi(pageSizeText) if err != nil || pageSize <= 0 { return req, errors.New("pageSize 必须为正整数") } req.PageSize = pageSize } tOpenGainLt101, err := parseOptionalBoolQuery(c, "tOpenGainLt101", "tOpenLessThan101", "t_open_gain_lt_101") if err != nil { return req, errors.New("tOpenGainLt101 必须为布尔值") } req.TOpenGainLt101 = tOpenGainLt101 breakTimeBefore1100, err := parseOptionalBoolQuery(c, "breakTimeBefore1100", "tBreakTimeBefore1100", "break_time_before_1100") if err != nil { return req, errors.New("breakTimeBefore1100 必须为布尔值") } req.BreakTimeBefore1100 = breakTimeBefore1100 return req, nil } func parseOptionalBoolQuery(c *gin.Context, keys ...string) (*bool, error) { for _, key := range keys { valueText, exists := c.GetQuery(key) if !exists { continue } valueText = strings.TrimSpace(valueText) if valueText == "" { continue } value, err := strconv.ParseBool(valueText) if err != nil { return nil, err } return &value, nil } return nil, nil } func (h *LimitBoardHandler) GetOpenThresholdGroups(c *gin.Context) { var req model.LimitBoardRequest if err := c.ShouldBindQuery(&req); err != nil || req.TradeDate == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "trade_date 参数不能为空"}) return } resp, err := h.Service.GetLimitOpenThresholdGroups(req.TradeDate) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, resp) }