From 6a74bfdcd40152aba11125f43199d7ccd6225e4a Mon Sep 17 00:00:00 2001 From: vipg Date: Mon, 22 Dec 2025 17:45:23 +0800 Subject: [PATCH] add --- infra/postgres/sql/03_trading_records.sql | 3 --- .../src/crud/create.go | 26 ++++++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/infra/postgres/sql/03_trading_records.sql b/infra/postgres/sql/03_trading_records.sql index e2617ab..dd2656b 100644 --- a/infra/postgres/sql/03_trading_records.sql +++ b/infra/postgres/sql/03_trading_records.sql @@ -3,10 +3,8 @@ -- ========================================================= \pset pager off \timing on --- 切换到目标数据库 \c postgres; --- 1 保证扩展存在(重复执行无害) CREATE EXTENSION IF NOT EXISTS "moddatetime" SCHEMA public; DO $$ @@ -14,7 +12,6 @@ BEGIN RAISE NOTICE '🚀============ cn_futures_trading_records 部署开始 ============🚀'; END $$; --- 2 建表(幂等) DO $$ BEGIN IF NOT EXISTS ( diff --git a/services/cn_futures_trading_records/src/crud/create.go b/services/cn_futures_trading_records/src/crud/create.go index 1ab5dd2..52bda32 100644 --- a/services/cn_futures_trading_records/src/crud/create.go +++ b/services/cn_futures_trading_records/src/crud/create.go @@ -7,8 +7,8 @@ import ( "encoding/json" "fmt" "net/http" + "reflect" "strconv" - "strings" "time" "github.com/gin-gonic/gin" @@ -17,7 +17,7 @@ import ( "go.uber.org/zap" ) -/* ---------- 公共 Payload 结构体 ---------- */ +/* ---------- 公共 Payload ---------- */ type Payload struct { Status int `csv:"status" json:"status" binding:"required,min=-1,max=1"` OpenYear int `csv:"open_year" json:"open_year" binding:"required,min=1900,max=2200"` @@ -38,7 +38,19 @@ type Payload struct { TickPrice float64 `csv:"tick_price" json:"tick_price" binding:"required"` DiffPnL float64 `csv:"diff_pnl" json:"diff_pnl" binding:"required"` TotalFee float64 `csv:"total_fee" json:"total_fee" binding:"required,min=0"` - ClosePnL float64 `csv:"close_pnl" json:"close_pnl" binding:"required"` // 客户端算好 + ClosePnL float64 `csv:"close_pnl" json:"close_pnl" binding:"required"` +} + +/* ---------- 包级常量:带 csv 标签的字段个数 ---------- */ +var payloadCSVCols int + +func init() { + typ := reflect.TypeOf(Payload{}) + for i := 0; i < typ.NumField(); i++ { + if _, ok := typ.Field(i).Tag.Lookup("csv"); ok { + payloadCSVCols++ + } + } } /* ---------- 单条创建 ---------- */ @@ -180,14 +192,14 @@ func CreateBatchHandler(c *gin.Context) { var recordIDs []string for idx, row := range req.Rows { - if len(row) != 19 { // 19 列(含 ClosePnL) + if len(row) != payloadCSVCols { // ✅ 自动随结构体同步 tx.Rollback() - zap.L().Warn("⚠️ 字段数量不匹配", zap.String("req_id", reqID), zap.Int("row_index", idx), zap.Int("field_count", len(row))) - c.JSON(http.StatusOK, TradingRecordsBatchCreateResponse{Success: false, Message: "第 " + strconv.Itoa(idx+1) + " 行字段数量不足 19 个"}) + zap.L().Warn("⚠️ 字段数量不匹配", zap.String("req_id", reqID), zap.Int("row_index", idx), zap.Int("field_count", len(row)), zap.Int("expected", payloadCSVCols)) + c.JSON(http.StatusOK, TradingRecordsBatchCreateResponse{Success: false, Message: "第 " + strconv.Itoa(idx+1) + " 行字段数量不足 " + strconv.Itoa(payloadCSVCols) + " 个"}) return } - // 用 gocsv 一次性映射 + // 一次性映射 var p Payload if err := gocsv.UnmarshalCSV(csv.NewReader(bytes.NewReader([]byte(strings.Join(row, ",")+"\n"))), &p); err != nil { tx.Rollback()