package handlers import ( "net/http" "strings" "stock-user-system/internal/datasource" "stock-user-system/internal/models" "github.com/gin-gonic/gin" "gorm.io/gorm" "gorm.io/gorm/clause" ) var validExchanges = map[string]string{ "SSE": "上交所", "SZSE": "深交所", "BSE": "北交所", } func toModelStock(s datasource.StockBasic) models.Stock { return models.Stock{ TsCode: s.TsCode, Symbol: s.Symbol, Name: s.Name, Area: s.Area, Industry: s.Industry, Fullname: s.Fullname, Enname: s.Enname, Cnspell: s.Cnspell, Market: s.Market, Exchange: s.Exchange, CurrType: s.CurrType, ListStatus: s.ListStatus, ListDate: s.ListDate, DelistDate: s.DelistDate, IsHs: s.IsHs, ActName: s.ActName, ActEntType: s.ActEntType, } } // DataSyncHandler 处理数据同步相关接口。 type DataSyncHandler struct { DB *gorm.DB client *datasource.Client } // NewDataSyncHandler 创建数据同步处理器。 func NewDataSyncHandler(db *gorm.DB) *DataSyncHandler { return &DataSyncHandler{ DB: db, client: datasource.NewClient(), } } type initStocksResponse struct { Count int `json:"count"` Message string `json:"message"` } // InitStocks 从 Tushare 拉取全部上市股票列表并写入数据库。 func (h *DataSyncHandler) InitStocks(c *gin.Context) { stocks, err := h.client.ListStocks() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } records := make([]models.Stock, 0, len(stocks)) for _, s := range stocks { records = append(records, toModelStock(s)) } if err := h.DB.Exec("TRUNCATE TABLE stocks RESTART IDENTITY").Error; err != nil { if !strings.Contains(err.Error(), "does not exist") { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "清空旧数据失败: " + err.Error()}) return } } if err := h.DB.CreateInBatches(records, 500).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "写入股票列表失败: " + err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": initStocksResponse{ Count: len(records), Message: "股票列表初始化完成", }, }) } type syncStocksByExchangeResponse struct { Exchange string `json:"exchange"` Count int `json:"count"` Message string `json:"message"` } // SyncStocksByExchange 按交易所从 Tushare 同步股票基础信息。 func (h *DataSyncHandler) SyncStocksByExchange(c *gin.Context) { exchange := strings.ToUpper(strings.TrimSpace(c.Param("exchange"))) if _, ok := validExchanges[exchange]; !ok { c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "无效的交易所代码,支持 SSE/SZSE/BSE"}) return } stocks, err := h.client.ListStocksByExchange(exchange) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": err.Error()}) return } records := make([]models.Stock, 0, len(stocks)) for _, s := range stocks { records = append(records, toModelStock(s)) } if err := h.DB.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "ts_code"}}, UpdateAll: true, }).CreateInBatches(records, 500).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "写入股票列表失败: " + err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": syncStocksByExchangeResponse{ Exchange: exchange, Count: len(records), Message: validExchanges[exchange] + "股票同步完成", }, }) }