From 7f49c0cdc075f88edb5e4c92769383b659f89df3 Mon Sep 17 00:00:00 2001 From: vipg Date: Wed, 26 Nov 2025 16:06:00 +0800 Subject: [PATCH] add --- backend/src/logic4variety/read.go | 241 +++++++++++++++++++++++++++++- 1 file changed, 240 insertions(+), 1 deletion(-) diff --git a/backend/src/logic4variety/read.go b/backend/src/logic4variety/read.go index 92360ce..3bdd8c3 100644 --- a/backend/src/logic4variety/read.go +++ b/backend/src/logic4variety/read.go @@ -1 +1,240 @@ -package logic4variety \ No newline at end of file +package logic4exchange + +import ( + "asset_assistant/db" + "net/http" + "strconv" + "strings" + "time" + + "fmt" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "go.uber.org/zap" +) + +// ReadRequest 读取请求参数结构 +type ReadRequest struct { + ExchangeID string `form:"exchange_id"` // 交易所ID,可选 + Name string `form:"name"` // 交易所名称,可选 + Code string `form:"code"` // 交易所代码,可选 + ShortName string `form:"short_name"` // 交易所短名称,新增查询条件 + Page string `form:"page"` // 页码,可选 + PageSize string `form:"page_size"` // 每页条数,可选 +} + +// ReadData 读取响应数据结构 +type ReadData struct { + Total int64 `json:"total"` // 总条数 + Page int `json:"page"` // 当前页码 + PageSize int `json:"page_size"` // 每页条数 + Items []ExchangeInfoViewItem `json:"items"` // 数据列表 +} + +// ExchangeInfoViewItem 视图数据项结构 +type ExchangeInfoViewItem struct { + ExchangeID string `json:"exchange_id"` // 交易所ID + Name string `json:"name"` // 交易所名称 + Code string `json:"code"` // 交易所代码 + ShortName string `json:"short_name"` // 新增:交易所短名称 +} + +// ReadResponse 读取响应结构 +type ReadResponse struct { + Success bool `json:"success"` // 操作是否成功 + Message string `json:"message"` // 提示信息 + Data ReadData `json:"data"` // 响应数据 +} + +// ReadHandler 处理信息查询逻辑 +func ReadHandler(c *gin.Context) { + startTime := time.Now() + // 获取或生成请求ID + reqID := c.Request.Header.Get("X-ReadRequest-ID") + if reqID == "" { + reqID = uuid.New().String() + zap.L().Debug("✨ 生成新的请求ID", zap.String("req_id", reqID)) + } + + // 记录请求接收日志 + zap.L().Info("📥 收到交易所查询请求", + zap.String("req_id", reqID), + zap.String("path", c.Request.URL.Path), + zap.String("method", c.Request.Method), + ) + + // 绑定请求参数 + var req ReadRequest + if err := c.ShouldBindQuery(&req); err != nil { + zap.L().Warn("⚠️ 请求参数解析失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusBadRequest, ReadResponse{ + Success: false, + Message: "请求参数格式错误", + }) + return + } + + // 验证查询条件至少有一个不为空(新增short_name作为可选条件) + if req.ExchangeID == "" && req.Name == "" && req.Code == "" && req.ShortName == "" { + zap.L().Warn("⚠️ 请求参数验证失败", + zap.String("req_id", reqID), + zap.String("reason", "exchange_id、name、code、short_name不能同时为空"), + ) + c.JSON(http.StatusBadRequest, ReadResponse{ + Success: false, + Message: "请求参数错误:exchange_id、name、code、short_name不能同时为空", + }) + return + } + + // 处理分页参数默认值 + page, err := strconv.Atoi(req.Page) + if err != nil || page < 1 { + page = 1 + } + pageSize, err := strconv.Atoi(req.PageSize) + if err != nil || pageSize < 1 { + pageSize = 20 + } + + zap.L().Debug("✅ 请求参数验证通过", + zap.String("req_id", reqID), + zap.String("exchange_id", req.ExchangeID), + zap.String("name", req.Name), + zap.String("code", req.Code), + zap.String("short_name", req.ShortName), // 新增短名称日志 + zap.Int("page", page), + zap.Int("page_size", pageSize), + ) + + // 构建查询条件和参数 + whereClauses := []string{} + args := []interface{}{} + paramIndex := 1 + + if req.ExchangeID != "" { + whereClauses = append(whereClauses, "exchange_id = $"+strconv.Itoa(paramIndex)) + args = append(args, req.ExchangeID) + paramIndex++ + } + if req.Name != "" { + whereClauses = append(whereClauses, "name LIKE $"+strconv.Itoa(paramIndex)) + args = append(args, "%"+req.Name+"%") + paramIndex++ + } + // 新增:短名称查询条件 + if req.ShortName != "" { + whereClauses = append(whereClauses, "short_name LIKE $"+strconv.Itoa(paramIndex)) + args = append(args, "%"+req.ShortName+"%") + paramIndex++ + } + if req.Code != "" { + whereClauses = append(whereClauses, "code LIKE $"+strconv.Itoa(paramIndex)) + args = append(args, "%"+req.Code+"%") + paramIndex++ + } + + // 构建基础SQL(新增查询short_name字段) + baseSQL := "SELECT exchange_id, name, short_name, code FROM exchange_info_view" + countSQL := "SELECT COUNT(*) FROM exchange_info_view" + if len(whereClauses) > 0 { + whereStr := " WHERE " + strings.Join(whereClauses, " AND ") + baseSQL += whereStr + countSQL += whereStr + } + + // 计算分页偏移量 + offset := (page - 1) * pageSize + + // 拼接分页SQL + querySQL := fmt.Sprintf("%s ORDER BY exchange_id LIMIT $%d OFFSET $%d", baseSQL, paramIndex, paramIndex+1) + args = append(args, pageSize, offset) + + // 查询总条数 + var total int64 + countArgs := args[:len(args)-2] // 排除分页参数 + err = db.DB.QueryRow(countSQL, countArgs...).Scan(&total) + if err != nil { + zap.L().Error("❌ 查询总条数失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "查询数据失败,请稍后重试", + }) + return + } + + // 执行分页查询 + rows, err := db.DB.Query(querySQL, args...) + if err != nil { + zap.L().Error("❌ 分页查询失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "查询数据失败,请稍后重试", + }) + return + } + defer rows.Close() + + // 处理查询结果(新增扫描short_name字段) + var items []ExchangeInfoViewItem + for rows.Next() { + var item ExchangeInfoViewItem + if err := rows.Scan(&item.ExchangeID, &item.Name, &item.ShortName, &item.Code); err != nil { + zap.L().Error("❌ 解析查询结果失败", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "数据处理失败,请稍后重试", + }) + return + } + items = append(items, item) + } + + // 检查行迭代过程中是否发生错误 + if err := rows.Err(); err != nil { + zap.L().Error("❌ 行迭代错误", + zap.String("req_id", reqID), + zap.Error(err), + ) + c.JSON(http.StatusInternalServerError, ReadResponse{ + Success: false, + Message: "查询数据失败,请稍后重试", + }) + return + } + + // 记录请求处理耗时 + duration := time.Since(startTime) + zap.L().Info("✅ 交易所查询请求处理完成", + zap.String("req_id", reqID), + zap.Int64("total", total), + zap.Int("page", page), + zap.Int("page_size", pageSize), + zap.Duration("duration", duration), + ) + + // 返回成功响应 + c.JSON(http.StatusOK, ReadResponse{ + Success: true, + Message: "查询成功", + Data: ReadData{ + Total: total, + Page: page, + PageSize: pageSize, + Items: items, + }, + }) +}