diff --git a/internal/database/db.go b/internal/database/db.go index ee42b00..75ba6b5 100644 --- a/internal/database/db.go +++ b/internal/database/db.go @@ -3,6 +3,7 @@ package database import ( "database/sql" "fmt" + "log" "os" _ "modernc.org/sqlite" @@ -14,9 +15,12 @@ var DB *sql.DB func InitDB(dbPath string) error { var err error + log.Printf("[DB] 初始化数据库: path=%s", dbPath) + // 确保数据库目录存在 dir := "./data" if _, err := os.Stat(dir); os.IsNotExist(err) { + log.Printf("[DB] 数据库目录不存在, 创建: %s", dir) os.MkdirAll(dir, 0755) } @@ -32,6 +36,7 @@ func InitDB(dbPath string) error { return fmt.Errorf("创建表失败: %w", err) } + log.Printf("[DB] 数据库初始化完成") return nil } diff --git a/internal/handler/config_handler.go b/internal/handler/config_handler.go index b61f371..96faee1 100644 --- a/internal/handler/config_handler.go +++ b/internal/handler/config_handler.go @@ -28,13 +28,19 @@ func NewConfigHandler(configPath string) *ConfigHandler { // GetConfigPrice 获取配置 // 先读 yaml(Port/TimerInterval/APIRateLimit/CallbackURL),再用数据库值覆盖价格字段 func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[GetConfigPrice] 收到请求, 来源IP: %s", clientIP) + h.mu.Lock() defer h.mu.Unlock() // 1. 加载yaml配置 cfg, err := config.Load(h.configPath) if err != nil { - log.Printf("[GetConfigPrice] 读取配置失败: %s", err.Error()) + log.Printf("[GetConfigPrice] 读取配置失败: %s, 来源IP: %s", err.Error(), clientIP) w.Header().Set("Content-Type", "application/json") w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"读取配置失败: %s"}`, err.Error()))) return @@ -56,6 +62,9 @@ func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) { // 同步全局配置 config.SetGlobal(cfg) + log.Printf("[GetConfigPrice] 返回配置: port=%s, new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d", + cfg.Port, cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex) + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "code": 200, @@ -70,6 +79,12 @@ func (h *ConfigHandler) GetConfigPrice(w http.ResponseWriter, r *http.Request) { func (h *ConfigHandler) SetConfigPrice(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(32 << 20) + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[SetConfigPrice] 收到请求, 来源IP: %s", clientIP) + h.mu.Lock() defer h.mu.Unlock() diff --git a/internal/handler/goods_handler.go b/internal/handler/goods_handler.go index a8c47fa..ddb34ea 100644 --- a/internal/handler/goods_handler.go +++ b/internal/handler/goods_handler.go @@ -25,8 +25,15 @@ func NewGoodsHandler(goodsService *service.GoodsService) *GoodsHandler { // QueryGoods 查询商品接口 func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[QueryGoods] 收到请求, 来源IP: %s, Method: %s", clientIP, r.Method) + // 只支持POST请求 if r.Method != http.MethodPost { + log.Printf("[QueryGoods] 方法不允许: %s, 来源IP: %s", r.Method, clientIP) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } @@ -34,8 +41,7 @@ func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) { // 读取原始body用于调试 bodyBytes, _ := io.ReadAll(r.Body) bodyStr := string(bodyBytes) - log.Printf("收到原始请求 Body: [%s]", bodyStr) - log.Printf("Content-Type: [%s]", r.Header.Get("Content-Type")) + log.Printf("[QueryGoods] 原始请求 Body: [%s], Content-Type: [%s]", bodyStr, r.Header.Get("Content-Type")) // 重新创建body供ParseForm使用 r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) @@ -44,33 +50,43 @@ func (h *GoodsHandler) QueryGoods(w http.ResponseWriter, r *http.Request) { if err := r.ParseMultipartForm(32 << 20); err != nil { // 尝试纯表单解析 if err := r.ParseForm(); err != nil { - log.Printf("ParseForm 失败: %v", err) + log.Printf("[QueryGoods] 参数解析失败: %v, 来源IP: %s", err, clientIP) http.Error(w, "Invalid request form", http.StatusBadRequest) return } } - // 调试日志 - log.Printf("解析结果 - isbn: [%s], book_name: [%s], author: [%s], publishing: [%s], out_id: [%s], quality: [%s], query_index: [%s], user_id: [%s], placeholder_down_price: [%s], min_shipping_fee: [%s], min_price: [%s] ", - r.FormValue("isbn"), r.FormValue("book_name"), r.FormValue("author"), r.FormValue("publishing"), - r.FormValue("out_id"), r.FormValue("quality"), - r.FormValue("query_index"), r.FormValue("user_id"), r.FormValue("placeholder_down_price"), r.FormValue("min_shipping_fee"), r.FormValue("min_price")) + isbn := r.FormValue("isbn") + bookName := r.FormValue("book_name") + author := r.FormValue("author") + publishing := r.FormValue("publishing") + outID := r.FormValue("out_id") + quality := r.FormValue("quality") + queryIndex := r.FormValue("query_index") + userID := r.FormValue("user_id") + placeholderDownPrice := r.FormValue("placeholder_down_price") + minShippingFee := r.FormValue("min_shipping_fee") + minPrice := r.FormValue("min_price") + + log.Printf("[QueryGoods] 解析参数完成 - isbn=[%s], book_name=[%s], author=[%s], publishing=[%s], out_id=[%s], quality=[%s], query_index=[%s], user_id=[%s], placeholder_down_price=[%s], min_shipping_fee=[%s], min_price=[%s]", + isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice) var req service.QueryRequest - req.ISBN = r.FormValue("isbn") - req.BookName = r.FormValue("book_name") - req.Author = r.FormValue("author") - req.Publishing = r.FormValue("publishing") - req.OutID = r.FormValue("out_id") - req.Quality = r.FormValue("quality") - req.QueryIndex, _ = strconv.Atoi(r.FormValue("query_index")) - req.UserID = r.FormValue("user_id") - req.PlaceholderDownPrice, _ = strconv.ParseFloat(r.FormValue("placeholder_down_price"), 64) - req.MinShippingFee, _ = strconv.ParseFloat(r.FormValue("min_shipping_fee"), 64) - req.MinPrice, _ = strconv.ParseFloat(r.FormValue("min_price"), 64) + req.ISBN = isbn + req.BookName = bookName + req.Author = author + req.Publishing = publishing + req.OutID = outID + req.Quality = quality + req.QueryIndex, _ = strconv.Atoi(queryIndex) + req.UserID = userID + req.PlaceholderDownPrice, _ = strconv.ParseFloat(placeholderDownPrice, 64) + req.MinShippingFee, _ = strconv.ParseFloat(minShippingFee, 64) + req.MinPrice, _ = strconv.ParseFloat(minPrice, 64) // 调用服务层 resp := h.goodsService.QueryGoods(&req) + log.Printf("[QueryGoods] 处理完成, ID=%d, Code=%d, Message=%s", resp.ID, resp.Code, resp.Message) // 返回响应 w.Header().Set("Content-Type", "application/json") diff --git a/internal/handler/kfz_handler.go b/internal/handler/kfz_handler.go index 8db9458..125fc7f 100644 --- a/internal/handler/kfz_handler.go +++ b/internal/handler/kfz_handler.go @@ -3,10 +3,12 @@ package handler import ( "encoding/json" "fmt" - "github.com/parnurzeal/gorequest" + "log" "net/http" "strings" "time" + + "github.com/parnurzeal/gorequest" ) // KfzHandler Kfz处理器 @@ -20,31 +22,43 @@ func NewKfzHandler() *KfzHandler { // KfzLogin 登录孔网并返回用户信息 func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[KfzLogin] 收到登录请求, 来源IP: %s", clientIP) + r.ParseMultipartForm(32 << 20) username := r.PostForm.Get("username") password := r.PostForm.Get("password") if username == "" || password == "" { + log.Printf("[KfzLogin] username或password为空, 来源IP: %s", clientIP) w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"code":500,"message":"username和password不能为空"}`)) return } + log.Printf("[KfzLogin] 开始登录孔网, username=%s, 来源IP: %s", username, clientIP) token, err := outKfzLogin(username, password) if err != nil { + log.Printf("[KfzLogin] 孔网登录失败: username=%s, 错误=%v, 来源IP: %s", username, err, clientIP) w.Header().Set("Content-Type", "application/json") w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error()))) return } + log.Printf("[KfzLogin] 孔网登录成功: username=%s, token=%s..., 来源IP: %s", username, token[:min(len(token), 10)], clientIP) userInfo, err := outKfzGetUserInfo(token) if err != nil { + log.Printf("[KfzLogin] 获取用户信息失败: username=%s, 错误=%v, 来源IP: %s", username, err, clientIP) w.Header().Set("Content-Type", "application/json") w.Write([]byte(fmt.Sprintf(`{"code":500,"message":"%s"}`, err.Error()))) return } userInfo.Token = token + log.Printf("[KfzLogin] 登录成功: username=%s, userId=%d, nickname=%s, 来源IP: %s", username, userInfo.UserID, userInfo.Nickname, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ @@ -54,6 +68,13 @@ func (h *KfzHandler) KfzLogin(w http.ResponseWriter, r *http.Request) { }) } +func min(a, b int) int { + if a < b { + return a + } + return b +} + /* * 孔网登录 * param username[string] 孔网用户名 diff --git a/internal/handler/token_handler.go b/internal/handler/token_handler.go index 85b7015..2bcac89 100644 --- a/internal/handler/token_handler.go +++ b/internal/handler/token_handler.go @@ -36,22 +36,27 @@ type TokenInput struct { // BatchAddTokens 批量添加Token(JSON数组: [{"username":"","token":""},...]) func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + if r.Method == http.MethodOptions { - w.WriteHeader(http.StatusOK) return } var inputs []TokenInput if err := json.NewDecoder(r.Body).Decode(&inputs); err != nil { - log.Printf("BatchAddTokens - decode error: %v", err) + log.Printf("[Token/BatchAdd] 请求体解析失败: %v, 来源IP: %s", err, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "invalid request body"}) return } - log.Printf("BatchAddTokens - received %d tokens", len(inputs)) + log.Printf("[Token/BatchAdd] 收到请求, 来源IP: %s, token数量: %d", clientIP, len(inputs)) if len(inputs) == 0 { + log.Printf("[Token/BatchAdd] 空数组, 来源IP: %s", clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 400, Message: "empty array"}) return @@ -59,21 +64,25 @@ func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) { // 逐条插入 var failed []TokenInput - for _, input := range inputs { + for i, input := range inputs { if input.Username == "" || input.Token == "" { + log.Printf("[Token/BatchAdd] 第%d条数据不完整(username或token为空), 跳过", i+1) failed = append(failed, input) continue } - _, err := h.tokenRepo.Insert(input.Username, input.Token, true) + id, err := h.tokenRepo.Insert(input.Username, input.Token, true) if err != nil { - log.Printf("BatchAddTokens - insert error: %v", err) + log.Printf("[Token/BatchAdd] 第%d条插入失败: username=%s, 错误=%v", i+1, input.Username, err) failed = append(failed, input) + } else { + log.Printf("[Token/BatchAdd] 第%d条插入成功: id=%d, username=%s", i+1, id, input.Username) } } w.Header().Set("Content-Type", "application/json") if len(failed) > 0 { + log.Printf("[Token/BatchAdd] 部分成功: 成功%d条, 失败%d条, 来源IP: %s", len(inputs)-len(failed), len(failed), clientIP) json.NewEncoder(w).Encode(TokenResponse{ Code: 207, Message: "partial success", @@ -82,31 +91,44 @@ func (h *TokenHandler) BatchAddTokens(w http.ResponseWriter, r *http.Request) { return } + log.Printf("[Token/BatchAdd] 全部成功: %d条, 来源IP: %s", len(inputs), clientIP) json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"}) } // GetAllTokens 查询所有Token func (h *TokenHandler) GetAllTokens(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[Token/GetAll] 收到请求, 来源IP: %s", clientIP) + if r.Method == http.MethodOptions { - w.WriteHeader(http.StatusOK) return } records, err := h.tokenRepo.GetAll() if err != nil { + log.Printf("[Token/GetAll] 查询失败: %v, 来源IP: %s", err, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) return } + log.Printf("[Token/GetAll] 查询成功: 共%d条记录, 来源IP: %s", len(records), clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records}) } // DeleteToken 删除Token func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[Token/Delete] 收到请求, 来源IP: %s", clientIP) + if r.Method == http.MethodOptions { - w.WriteHeader(http.StatusOK) return } @@ -122,25 +144,33 @@ func (h *TokenHandler) DeleteToken(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(idStr, 10, 64) if err != nil { + log.Printf("[Token/Delete] 参数id无效: %s, 来源IP: %s", idStr, clientIP) http.Error(w, "invalid id", http.StatusBadRequest) return } err = h.tokenRepo.Delete(id) if err != nil { + log.Printf("[Token/Delete] 删除失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) return } + log.Printf("[Token/Delete] 删除成功: id=%d, 来源IP: %s", id, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"}) } // UpdateToken 修改Token func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[Token/Update] 收到请求, 来源IP: %s", clientIP) + if r.Method == http.MethodOptions { - w.WriteHeader(http.StatusOK) return } @@ -155,6 +185,7 @@ func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(idStr, 10, 64) if err != nil { + log.Printf("[Token/Update] 参数id无效: %s, 来源IP: %s", idStr, clientIP) http.Error(w, "invalid id", http.StatusBadRequest) return } @@ -164,31 +195,41 @@ func (h *TokenHandler) UpdateToken(w http.ResponseWriter, r *http.Request) { isEnable = false } + log.Printf("[Token/Update] 更新: id=%d, username=%s, is_enable=%v, 来源IP: %s", id, username, isEnable, clientIP) err = h.tokenRepo.Update(id, username, token, isEnable) if err != nil { + log.Printf("[Token/Update] 更新失败: id=%d, 错误=%v, 来源IP: %s", id, err, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) return } + log.Printf("[Token/Update] 更新成功: id=%d, 来源IP: %s", id, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success"}) } // GetEnabledTokens 获取所有启用的Token func (h *TokenHandler) GetEnabledTokens(w http.ResponseWriter, r *http.Request) { + clientIP := r.RemoteAddr + if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" { + clientIP = forwarded + } + log.Printf("[Token/GetEnabled] 收到请求, 来源IP: %s", clientIP) + if r.Method == http.MethodOptions { - w.WriteHeader(http.StatusOK) return } records, err := h.tokenRepo.GetEnabledTokens() if err != nil { + log.Printf("[Token/GetEnabled] 查询失败: %v, 来源IP: %s", err, clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 500, Message: err.Error()}) return } + log.Printf("[Token/GetEnabled] 查询成功: 共%d条启用token, 来源IP: %s", len(records), clientIP) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(TokenResponse{Code: 200, Message: "success", Data: records}) } diff --git a/internal/repository/config_repository.go b/internal/repository/config_repository.go index c3f7526..5c053d5 100644 --- a/internal/repository/config_repository.go +++ b/internal/repository/config_repository.go @@ -3,6 +3,7 @@ package repository import ( "database/sql" "fmt" + "log" "kfz-goods-pricing/internal/database" ) @@ -26,11 +27,15 @@ func GetKfzConfig() (*KfzConfig, error) { ).Scan(&cfg.ID, &cfg.NewPrice, &cfg.PlaceholderDownPrice, &cfg.MinShippingFee, &cfg.MinPrice, &cfg.QueryIndex) if err == sql.ErrNoRows { + log.Printf("[Repo/Config] kfz_config表无数据") return nil, nil // 无数据 } if err != nil { + log.Printf("[Repo/Config] 查询kfz_config失败: %v", err) return nil, fmt.Errorf("查询kfz_config失败: %w", err) } + log.Printf("[Repo/Config] 查询成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d", + cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex) return &cfg, nil } @@ -40,6 +45,7 @@ func SaveKfzConfig(cfg *KfzConfig) error { var count int err := database.DB.QueryRow("SELECT COUNT(*) FROM kfz_config").Scan(&count) if err != nil { + log.Printf("[Repo/Config] 查询kfz_config数量失败: %v", err) return fmt.Errorf("查询kfz_config失败: %w", err) } @@ -49,16 +55,22 @@ func SaveKfzConfig(cfg *KfzConfig) error { cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex, ) if err != nil { + log.Printf("[Repo/Config] 插入配置失败: %v", err) return fmt.Errorf("插入kfz_config失败: %w", err) } + log.Printf("[Repo/Config] 插入配置成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d", + cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex) } else { _, err = database.DB.Exec( `UPDATE kfz_config SET new_price=?, placeholder_down_price=?, min_shipping_fee=?, min_price=?, query_index=? WHERE id=1`, cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex, ) if err != nil { + log.Printf("[Repo/Config] 更新配置失败: %v", err) return fmt.Errorf("更新kfz_config失败: %w", err) } + log.Printf("[Repo/Config] 更新配置成功: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d", + cfg.NewPrice, cfg.PlaceholderDownPrice, cfg.MinShippingFee, cfg.MinPrice, cfg.QueryIndex) } return nil } diff --git a/internal/repository/goods_repository.go b/internal/repository/goods_repository.go index 2bd0094..9fb5d26 100644 --- a/internal/repository/goods_repository.go +++ b/internal/repository/goods_repository.go @@ -3,6 +3,7 @@ package repository import ( "database/sql" "fmt" + "log" "kfz-goods-pricing/internal/database" ) @@ -40,14 +41,17 @@ func (r *GoodsRepository) Insert(isbn, bookName, author, publishing, outID, qual result, err := database.DB.Exec(query, isbn, bookName, author, publishing, outID, quality, queryIndex, userID, placeholderDownPrice, minShippingFee, minPrice) if err != nil { + log.Printf("[Repo/Goods] 插入记录失败: isbn=%s, out_id=%s, 错误=%v", isbn, outID, err) return 0, fmt.Errorf("插入记录失败: %w", err) } id, err := result.LastInsertId() if err != nil { + log.Printf("[Repo/Goods] 获取自增ID失败: %v", err) return 0, fmt.Errorf("获取自增ID失败: %w", err) } + log.Printf("[Repo/Goods] 插入成功: id=%d, isbn=%s, out_id=%s, min_price=%.2f", id, isbn, outID, minPrice) return id, nil } @@ -57,16 +61,23 @@ func (r *GoodsRepository) UpdatePrice(id int64, price, shippingFee, finalPrice f _, err := database.DB.Exec(query, price, shippingFee, finalPrice, id) if err != nil { + log.Printf("[Repo/Goods] 更新价格失败: id=%d, 错误=%v", id, err) return fmt.Errorf("更新价格失败: %w", err) } + log.Printf("[Repo/Goods] 更新价格成功: id=%d, price=%.2f, shipping_fee=%.2f, final_price=%.2f", id, price, shippingFee, finalPrice) return nil } // MarkFailed 标记查询失败,fail_count+1,更新updated_at func (r *GoodsRepository) MarkFailed(id int64) { query := `UPDATE goods_pricing SET fail_count = fail_count + 1, updated_at = CURRENT_TIMESTAMP WHERE id = ?` - database.DB.Exec(query, id) + _, err := database.DB.Exec(query, id) + if err != nil { + log.Printf("[Repo/Goods] 标记失败: id=%d, 错误=%v", id, err) + } else { + log.Printf("[Repo/Goods] 标记失败成功: id=%d", id) + } } // GetByID 根据ID查询记录 @@ -144,6 +155,7 @@ func (r *GoodsRepository) GetAllOrderByUpdatedAt() (*GoodsPricing, error) { if err == sql.ErrNoRows { return nil, nil } + log.Printf("[Repo/Goods] 查询待处理记录失败: %v", err) return nil, fmt.Errorf("查询记录失败: %w", err) } @@ -166,5 +178,6 @@ func (r *GoodsRepository) GetAllOrderByUpdatedAt() (*GoodsPricing, error) { record.MinPrice = minPrice.Float64 } + log.Printf("[Repo/Goods] 查询到待处理记录: id=%d, isbn=%s, book_name=%s, fail_count=%d", record.ID, record.ISBN, record.BookName, record.FailCount) return &record, nil } diff --git a/internal/service/goods_service.go b/internal/service/goods_service.go index d9df0d4..3e305f6 100644 --- a/internal/service/goods_service.go +++ b/internal/service/goods_service.go @@ -67,6 +67,7 @@ type QueryResponse struct { // QueryGoods 查询商品信息 func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse { if req.ISBN == "0" { + log.Printf("[QueryGoods] ISBN为0, 跳过处理") return &QueryResponse{ Code: 200, Message: "success", @@ -76,12 +77,15 @@ func (s *GoodsService) QueryGoods(req *QueryRequest) *QueryResponse { // 插入入参记录到数据库 id, err := s.goodsRepository.Insert(req.ISBN, req.BookName, req.Author, req.Publishing, req.OutID, req.Quality, req.UserID, req.QueryIndex, req.PlaceholderDownPrice, req.MinShippingFee, req.MinPrice) if err != nil { + log.Printf("[QueryGoods] 保存记录失败: isbn=%s, out_id=%s, user_id=%s, 错误=%v", req.ISBN, req.OutID, req.UserID, err) return &QueryResponse{ Code: 500, Message: fmt.Sprintf("保存记录失败: %v", err), } } + log.Printf("[QueryGoods] 记录保存成功: id=%d, isbn=%s, book_name=%s, out_id=%s, user_id=%s", id, req.ISBN, req.BookName, req.OutID, req.UserID) + return &QueryResponse{ Code: 200, Message: "success", @@ -135,6 +139,7 @@ func (s *GoodsService) sendCallback(outID, userID string, price, shippingFee flo // StartTimerScheduler 启动定时器 func (s *GoodsService) StartTimerScheduler(intervalSeconds int) { + log.Printf("[TimerScheduler] 定时器启动, 间隔=%d秒", intervalSeconds) ticker := time.NewTicker(time.Duration(intervalSeconds) * time.Second) go func() { for range ticker.C { @@ -145,23 +150,29 @@ func (s *GoodsService) StartTimerScheduler(intervalSeconds int) { // syncGoodsPricing 定时同步商品价格 func (s *GoodsService) syncGoodsPricing() { - //cfg := config.GetGlobal() + log.Printf("[syncGoodsPricing] ===== 开始执行定时同步任务 =====") + // 查询数据库数据 kfzConfig, err := repository.GetKfzConfig() if err != nil { - log.Printf("获取config数据库数据失败: %v", err) + log.Printf("[syncGoodsPricing] 获取config数据库数据失败: %v", err) return } + log.Printf("[syncGoodsPricing] 全局配置: new_price=%.2f, placeholder_down_price=%.2f, min_shipping_fee=%.2f, min_price=%.2f, query_index=%d", + kfzConfig.NewPrice, kfzConfig.PlaceholderDownPrice, kfzConfig.MinShippingFee, kfzConfig.MinPrice, kfzConfig.QueryIndex) // 查询一条记录,按fail_count升序、updated_at倒序 record, err := s.goodsRepository.GetAllOrderByUpdatedAt() if err != nil { - log.Printf("定时任务查询失败: %v", err) + log.Printf("[syncGoodsPricing] 查询待处理记录失败: %v", err) return } if record == nil { + log.Printf("[syncGoodsPricing] 没有待处理的记录, 跳过本次同步") return } + log.Printf("[syncGoodsPricing] 获取到待处理记录: id=%d, isbn=%s, book_name=%s, out_id=%s, fail_count=%d", + record.ID, record.ISBN, record.BookName, record.OutID, record.FailCount) // 限流等待 s.rateLimitWait() @@ -172,33 +183,45 @@ func (s *GoodsService) syncGoodsPricing() { var finalPrice float64 // 查询孔网数据 + log.Printf("[syncGoodsPricing] 开始查询孔网数据: id=%d, isbn=%s, book_name=%s", record.ID, record.ISBN, record.BookName) bookInfo, err := s.outGetAllGoods(record.ISBN, record.BookName, record.Author, record.Publishing, record.Quality, record.QueryIndex) if err != nil { + log.Printf("[syncGoodsPricing] 查询孔网失败: id=%d, 错误=%v", record.ID, err) if kfzConfig.NewPrice == 0 { s.goodsRepository.MarkFailed(record.ID) - log.Printf("定时任务[%d]查询孔网失败(fail_count=%d): %v", record.ID, record.FailCount+1, err) + log.Printf("[syncGoodsPricing] 标记失败: id=%d, fail_count=%d, new_price=0不启用兜底", record.ID, record.FailCount+1) return } finalPrice = kfzConfig.NewPrice + log.Printf("[syncGoodsPricing] 查询失败, 启用兜底价格: finalPrice=%.2f (new_price)", finalPrice) } else { // 查询成功,更新价格 price, _ = strconv.ParseFloat(bookInfo.Price, 64) shippingFee, _ = strconv.ParseFloat(bookInfo.ShippingFee, 64) totalPrice := price + shippingFee + log.Printf("[syncGoodsPricing] 孔网数据: id=%d, price=%.2f, shipping_fee=%.2f, total=%.2f", record.ID, price, shippingFee, totalPrice) + log.Printf("[syncGoodsPricing] 计算参数: placeholder_down_price=%.2f, min_shipping_fee=%.2f, kfzConfig.min_price=%.2f", + record.PlaceholderDownPrice, record.MinShippingFee, kfzConfig.MinPrice) + finalPrice = totalPrice - record.PlaceholderDownPrice - record.MinShippingFee + log.Printf("[syncGoodsPricing] 减去占位降价和运费后: finalPrice=%.2f", finalPrice) + if finalPrice < kfzConfig.MinPrice { + log.Printf("[syncGoodsPricing] 价格低于最低书价, 使用最低书价: %.2f -> %.2f", finalPrice, kfzConfig.MinPrice) finalPrice = kfzConfig.MinPrice } // 保留两位小数 + beforeRound := finalPrice finalPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", finalPrice), 64) + log.Printf("[syncGoodsPricing] 最终价格取两位小数: %.2f -> %.2f", beforeRound, finalPrice) } if err := s.goodsRepository.UpdatePrice(record.ID, price, shippingFee, finalPrice); err != nil { - log.Printf("定时任务[%d]更新价格失败: %v", record.ID, err) + log.Printf("[syncGoodsPricing] 更新价格失败: id=%d, 错误=%v", record.ID, err) return } - log.Printf("定时任务[%d]更新成功: price=%.2f, shipping_fee=%.2f", record.ID, price, shippingFee) + log.Printf("[syncGoodsPricing] 更新成功: id=%d, price=%.2f, shipping_fee=%.2f, final_price=%.2f", record.ID, price, shippingFee, finalPrice) // 调用回调 s.sendCallback(record.OutID, record.UserID, finalPrice, record.MinShippingFee, kfzConfig.MinPrice) @@ -211,8 +234,10 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin // 从数据库获取启用的token列表 tokens, err := s.tokenRepository.GetEnabledTokens() if err != nil || len(tokens) == 0 { + log.Printf("[outGetAllGoods] 没有可用的token, 查询终止") return nil, fmt.Errorf("没有可用的token") } + log.Printf("[outGetAllGoods] 可用token数量: %d", len(tokens)) // 轮询选择token s.tokenMu.Lock() @@ -222,8 +247,8 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin s.tokenMu.Unlock() token := tokens[currentIdx].Token + log.Printf("[outGetAllGoods] 使用token索引: %d/%d, username=%s", currentIdx, len(tokens), tokens[currentIdx].Username) - //kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&quaSelect=2" kfzUrl := "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list?dataType=0&page=1&sortType=7&userArea=13003000000&quaSelect=2" // 整理查询参数-加上排序 @@ -260,6 +285,8 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin // 加入查询参数 kfzUrl = kfzUrl + "&actionPath=" + actionPath + log.Printf("[outGetAllGoods] 请求孔网URL: %s", kfzUrl) + // 创建HTTP客户端 requestSpt := gorequest.New() @@ -267,7 +294,6 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin if s.proxy != "" { requestSpt.Proxy(s.proxy) } - fmt.Println("请求地址:", kfzUrl) // 发送请求 respSpt, bodySpt, errsSpt := requestSpt.Get(kfzUrl). Set("Cookie", fmt.Sprintf("PHPSESSID=%s", token)). @@ -280,16 +306,16 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin // 错误处理 if len(errsSpt) > 0 { + log.Printf("[outGetAllGoods] 孔网请求失败: %v", errsSpt) return nil, fmt.Errorf("请求失败: %v", errsSpt) } // 检查HTTP状态码 if respSpt.StatusCode != http.StatusOK { + log.Printf("[outGetAllGoods] 孔网HTTP错误: %s", respSpt.Status) return nil, fmt.Errorf("HTTP错误: %s", respSpt.Status) } - fmt.Println("响应数据:", bodySpt) - // 解析响应 var apiSptResp struct { Status int `json:"status"` @@ -318,16 +344,19 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin // 解析JSON if err := json.Unmarshal([]byte(bodySpt), &apiSptResp); err != nil { + log.Printf("[outGetAllGoods] 解析孔网响应JSON失败: %v", err) return nil, fmt.Errorf("解析JSON失败: %w", err) } if apiSptResp.Status != 1 { + log.Printf("[outGetAllGoods] 孔网API返回错误: message=%s, errType=%s", apiSptResp.Message, apiSptResp.ErrType) return nil, fmt.Errorf("错误信息: %v,状态码: %s", apiSptResp.Message, apiSptResp.ErrType) } bookInfo := &model.BookInfo{} if apiSptResp.Data.ItemResponse.Total > 0 && len(apiSptResp.Data.ItemResponse.List) > 0 { + log.Printf("[outGetAllGoods] 孔网搜索成功: 总共%d条结果, query_index=%d", apiSptResp.Data.ItemResponse.Total, queryIndex) if queryIndex > 0 && queryIndex <= len(apiSptResp.Data.ItemResponse.List) { goodsInfo := apiSptResp.Data.ItemResponse.List[queryIndex-1] bookInfo.BookName = goodsInfo.Title @@ -339,6 +368,7 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin for _, shipping := range goodsInfo.Postage.ShippingList { bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee) } + log.Printf("[outGetAllGoods] 取第%d条结果: title=%s, price=%s, shipping=%s", queryIndex, bookInfo.BookName, bookInfo.Price, bookInfo.ShippingFee) } else { goodsInfo := apiSptResp.Data.ItemResponse.List[len(apiSptResp.Data.ItemResponse.List)-1] bookInfo.BookName = goodsInfo.Title @@ -350,9 +380,11 @@ func (s *GoodsService) outGetAllGoods(isbn string, bookName string, author strin for _, shipping := range goodsInfo.Postage.ShippingList { bookInfo.ShippingFee = fmt.Sprintf("%.2f", shipping.ShippingFee) } + log.Printf("[outGetAllGoods] query_index无效, 取最后一条: title=%s, price=%s, shipping=%s", bookInfo.BookName, bookInfo.Price, bookInfo.ShippingFee) } return bookInfo, nil } + log.Printf("[outGetAllGoods] 孔网搜索无结果: total=%d", apiSptResp.Data.ItemResponse.Total) return nil, fmt.Errorf("查询失败,没有数据!") }