From c0a5834ab49c97ffcbb747d5112d04f977e81902 Mon Sep 17 00:00:00 2001 From: laoboli <1293528695@qq.com> Date: Wed, 19 Mar 2025 16:50:48 +0800 Subject: [PATCH] feat: hr save. --- controllers/train.go | 69 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 3 +- models/training.go | 34 ++++++++++++++++++++++ routes/routes.go | 10 +++++-- 4 files changed, 112 insertions(+), 4 deletions(-) diff --git a/controllers/train.go b/controllers/train.go index f402094..cd73558 100644 --- a/controllers/train.go +++ b/controllers/train.go @@ -2,11 +2,80 @@ package controllers import ( "github.com/gin-gonic/gin" + "gorm.io/gorm" + "gorm.io/gorm/clause" "hr_receiver/config" "hr_receiver/models" "net/http" ) +type TrainingController struct { + DB *gorm.DB +} + +func NewTrainingController() *TrainingController { + return &TrainingController{DB: config.DB} +} + +// 接收训练记录 +func (tc *TrainingController) CreateTrainingRecord(c *gin.Context) { + var record models.TrainRecord + + // 绑定并验证JSON数据 + if err := c.ShouldBindJSON(&record); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + // 使用事务保存数据[4](@ref) + err := tc.DB.Transaction(func(tx *gorm.DB) error { + // 保存主记录 + if err := tx.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "train_id"}}, // 指定冲突的列 + DoUpdates: clause.Assignments(map[string]interface{}{ + "max_heart_rate": record.MaxHeartRate, + "start_time": record.StartTime, + "end_time": record.EndTime, + "duration": record.Duration, + "people_num": record.PeopleNum, + "name": record.Name, + "evaluation": record.Evaluation, + }), + }).Omit("HeartRates", "belts").Create(&record).Error; err != nil { + return err + } + + // 保存关联的心率数据 + for i := range record.HeartRates { + if err := tx.Clauses( + clause.OnConflict{ + Columns: []clause.Column{{Name: "identifier"}}, // 指定冲突的列 + DoUpdates: clause.Assignments(map[string]interface{}{"value": record.HeartRates[i].Value, "time": record.HeartRates[i].Time}), + }, + ).Create(&record.HeartRates[i]).Error; err != nil { + + return err + } + } + + //// 保存腰带关联关系 + //if len(record.Belts) > 0 { + // if err := tx.Model(&record).Association("Belts").Replace(record.Belts); err != nil { + // return err + // } + //} + + return nil + }) + + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusCreated, record) +} + func ReceiveTrainingData(c *gin.Context) { var data models.TrainingData diff --git a/main.go b/main.go index 98e4fd3..5095b42 100644 --- a/main.go +++ b/main.go @@ -13,8 +13,9 @@ func main() { // 连接数据库 config.ConnectDB() + config.DB.Debug() // 自动迁移模型 - config.DB.AutoMigrate(&models.TrainingData{}) + config.DB.AutoMigrate(&models.TrainRecord{}, &models.TrainingData{}, &models.Belt{}, &models.HeartRate{}) // 启动服务 r := routes.SetupRouter() diff --git a/models/training.go b/models/training.go index f9ed52c..fdd5a44 100644 --- a/models/training.go +++ b/models/training.go @@ -9,3 +9,37 @@ type TrainingData struct { Probability float64 `gorm:"type:decimal(5,4)" json:"probability"` SessionID string `gorm:"index" json:"session_id"` } + +// 对应Flutter的Belt结构 +type Belt struct { + gorm.Model + Addr string `gorm:"uniqueIndex;size:255" json:"addr"` // 对应Dart的addr字段[6](@ref) + BID uint `gorm:"column:bid" json:"bid"` // 对应Dart的bid字段 + Name string `gorm:"size:100" json:"name"` +} + +// 对应Flutter的HeartRate结构 +type HeartRate struct { + gorm.Model + TrainId uint `gorm:"column:train_id; index" json:"trainId"` // 外键关联训练记录[4](@ref) + BeltId uint `gorm:"column:belt_id;index" json:"bid"` // 对应Dart的bid字段 + BeltAddr string `gorm:"column:belt_addr;size:255" json:"beltAddr"` // 对应Dart的beltAddr字段 + Time int64 `gorm:"type:bigint" json:"time"` // 保持与前端一致的毫秒时间戳[3](@ref) + Value int `gorm:"type:int" json:"value"` + Identifier string `gorm:"uniqueIndex;type:varchar(255)" json:"identifier"` +} + +// 对应Flutter的TrainRecord结构 +type TrainRecord struct { + gorm.Model + TrainId uint `gorm:"uniqueIndex" json:"tid"` // 对应Dart的tid字段 + StartTime int64 `gorm:"type:bigint" json:"time"` // 开始时间戳 + EndTime int64 `gorm:"type:bigint" json:"endTime"` // 结束时间戳[3](@ref) + Name string `gorm:"size:100" json:"name"` + MaxHeartRate int `gorm:"type:int" json:"maxHeartRate"` + Duration int `gorm:"type:int" json:"duration"` // 持续时间(秒) + PeopleNum int `gorm:"type:int" json:"peopleNum"` + Evaluation string `gorm:"size:50" json:"evaluation"` + Belts []Belt `gorm:"many2many:train_record_belts;" json:"belts"` // 多对多关联[4](@ref) + HeartRates []HeartRate `gorm:"foreignKey:TrainId;references:TrainId" json:"heart_rates"` +} diff --git a/routes/routes.go b/routes/routes.go index afab4f4..4c4d7cd 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -7,11 +7,15 @@ import ( func SetupRouter() *gin.Engine { r := gin.Default() + trainingController := controllers.NewTrainingController() - api := r.Group("/api/v1") + v1 := r.Group("/api/v1") { - api.POST("/training", controllers.ReceiveTrainingData) + records := v1.Group("/train-records") + { + records.POST("", trainingController.CreateTrainingRecord) + // 可扩展其他路由:GET, PUT, DELETE等 + } } - return r }