refactor(model): 重构数据模型结构
- 将 Word 和 MemoryRecord 结构体拆分为独立文件 - 创建 request 包用于存放请求结构体 - 创建 response 包用于存放响应结构体 - 将 YoudaoResponse 移至独立模型文件 - 更新服务层接口参数类型为新的请求响应结构体 - 修改处理器层导入路径以使用新包结构
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"memora-api/internal/model"
|
"memora-api/internal/request"
|
||||||
"memora-api/internal/service"
|
"memora-api/internal/service"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -22,7 +22,7 @@ func NewWordHandler(wordService *service.WordService) *WordHandler {
|
|||||||
|
|
||||||
// 添加单词(记忆模式)
|
// 添加单词(记忆模式)
|
||||||
func (h *WordHandler) AddWord(c *gin.Context) {
|
func (h *WordHandler) AddWord(c *gin.Context) {
|
||||||
var req model.AddWordRequest
|
var req request.AddWordRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
@@ -69,7 +69,7 @@ func (h *WordHandler) GetReviewWords(c *gin.Context) {
|
|||||||
|
|
||||||
// 提交复习答案
|
// 提交复习答案
|
||||||
func (h *WordHandler) SubmitReview(c *gin.Context) {
|
func (h *WordHandler) SubmitReview(c *gin.Context) {
|
||||||
var req model.ReviewAnswerRequest
|
var req request.ReviewAnswerRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
|
|||||||
21
memora-api/internal/model/memory_record.go
Normal file
21
memora-api/internal/model/memory_record.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type MemoryRecord struct {
|
||||||
|
ID int64 `json:"id" gorm:"primaryKey"`
|
||||||
|
WordID int64 `json:"word_id" gorm:"index;not null"`
|
||||||
|
UserID int64 `json:"user_id" gorm:"index;default:1"`
|
||||||
|
CorrectCount int `json:"correct_count" gorm:"default:0"`
|
||||||
|
TotalCount int `json:"total_count" gorm:"default:0"`
|
||||||
|
MasteryLevel int `json:"mastery_level" gorm:"default:0"`
|
||||||
|
LastReviewedAt *time.Time `json:"last_reviewed_at"`
|
||||||
|
NextReviewAt *time.Time `json:"next_review_at" gorm:"index"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
Word *Word `json:"word,omitempty" gorm:"foreignKey:WordID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (MemoryRecord) TableName() string {
|
||||||
|
return "memory_records"
|
||||||
|
}
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Word struct {
|
|
||||||
ID int64 `json:"id" gorm:"primaryKey"`
|
|
||||||
Word string `json:"word" gorm:"size:100;uniqueIndex;not null"`
|
|
||||||
PhoneticUK string `json:"phonetic_uk" gorm:"size:255"`
|
|
||||||
PhoneticUS string `json:"phonetic_us" gorm:"size:255"`
|
|
||||||
AudioUK string `json:"audio_uk" gorm:"size:500"`
|
|
||||||
AudioUS string `json:"audio_us" gorm:"size:500"`
|
|
||||||
PartOfSpeech string `json:"part_of_speech" gorm:"size:50"`
|
|
||||||
Definition string `json:"definition" gorm:"type:text"`
|
|
||||||
ExampleSentence string `json:"example_sentence" gorm:"type:text"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (Word) TableName() string {
|
|
||||||
return "words"
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemoryRecord struct {
|
|
||||||
ID int64 `json:"id" gorm:"primaryKey"`
|
|
||||||
WordID int64 `json:"word_id" gorm:"index;not null"`
|
|
||||||
UserID int64 `json:"user_id" gorm:"index;default:1"`
|
|
||||||
CorrectCount int `json:"correct_count" gorm:"default:0"`
|
|
||||||
TotalCount int `json:"total_count" gorm:"default:0"`
|
|
||||||
MasteryLevel int `json:"mastery_level" gorm:"default:0"`
|
|
||||||
LastReviewedAt *time.Time `json:"last_reviewed_at"`
|
|
||||||
NextReviewAt *time.Time `json:"next_review_at" gorm:"index"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
Word *Word `json:"word,omitempty" gorm:"foreignKey:WordID"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (MemoryRecord) TableName() string {
|
|
||||||
return "memory_records"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 请求响应结构
|
|
||||||
type AddWordRequest struct {
|
|
||||||
Word string `json:"word" binding:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReviewAnswerRequest struct {
|
|
||||||
RecordID int64 `json:"record_id" binding:"required"`
|
|
||||||
Answer string `json:"answer" binding:"required"`
|
|
||||||
Mode string `json:"mode" binding:"required"` // spelling, en2cn, cn2en
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReviewResult struct {
|
|
||||||
Word *Word `json:"word"`
|
|
||||||
Correct bool `json:"correct"`
|
|
||||||
Answer string `json:"answer"`
|
|
||||||
CorrectAns string `json:"correct_ans,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 有道API响应 (标准API)
|
|
||||||
type YoudaoResponse struct {
|
|
||||||
Query string `json:"query"`
|
|
||||||
Translation []string `json:"translation"`
|
|
||||||
Basic struct {
|
|
||||||
Phonetic string `json:"phonetic"`
|
|
||||||
UkPhonetic string `json:"uk-phonetic"`
|
|
||||||
UsPhonetic string `json:"us-phonetic"`
|
|
||||||
ExamType []string `json:"exam_type"`
|
|
||||||
Wfs []struct {
|
|
||||||
Wf struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
} `json:"wf"`
|
|
||||||
Means []struct {
|
|
||||||
Mean struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
} `json:"mean"`
|
|
||||||
} `json:"means"`
|
|
||||||
} `json:"wfs"`
|
|
||||||
} `json:"basic"`
|
|
||||||
SpeakUrl string `json:"speakUrl"`
|
|
||||||
SpeakFile string `json:"speakFile"`
|
|
||||||
Web []struct {
|
|
||||||
Value []string `json:"value"`
|
|
||||||
} `json:"web"`
|
|
||||||
ErrorCode string `json:"errorCode"`
|
|
||||||
}
|
|
||||||
21
memora-api/internal/model/word.go
Normal file
21
memora-api/internal/model/word.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Word struct {
|
||||||
|
ID int64 `json:"id" gorm:"primaryKey"`
|
||||||
|
Word string `json:"word" gorm:"size:100;uniqueIndex;not null"`
|
||||||
|
PhoneticUK string `json:"phonetic_uk" gorm:"size:255"`
|
||||||
|
PhoneticUS string `json:"phonetic_us" gorm:"size:255"`
|
||||||
|
AudioUK string `json:"audio_uk" gorm:"size:500"`
|
||||||
|
AudioUS string `json:"audio_us" gorm:"size:500"`
|
||||||
|
PartOfSpeech string `json:"part_of_speech" gorm:"size:50"`
|
||||||
|
Definition string `json:"definition" gorm:"type:text"`
|
||||||
|
ExampleSentence string `json:"example_sentence" gorm:"type:text"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Word) TableName() string {
|
||||||
|
return "words"
|
||||||
|
}
|
||||||
28
memora-api/internal/model/youdao.go
Normal file
28
memora-api/internal/model/youdao.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type YoudaoResponse struct {
|
||||||
|
Query string `json:"query"`
|
||||||
|
Translation []string `json:"translation"`
|
||||||
|
Basic struct {
|
||||||
|
Phonetic string `json:"phonetic"`
|
||||||
|
UkPhonetic string `json:"uk-phonetic"`
|
||||||
|
UsPhonetic string `json:"us-phonetic"`
|
||||||
|
ExamType []string `json:"exam_type"`
|
||||||
|
Wfs []struct {
|
||||||
|
Wf struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"wf"`
|
||||||
|
Means []struct {
|
||||||
|
Mean struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
} `json:"mean"`
|
||||||
|
} `json:"means"`
|
||||||
|
} `json:"wfs"`
|
||||||
|
} `json:"basic"`
|
||||||
|
SpeakUrl string `json:"speakUrl"`
|
||||||
|
SpeakFile string `json:"speakFile"`
|
||||||
|
Web []struct {
|
||||||
|
Value []string `json:"value"`
|
||||||
|
} `json:"web"`
|
||||||
|
ErrorCode string `json:"errorCode"`
|
||||||
|
}
|
||||||
11
memora-api/internal/request/word.go
Normal file
11
memora-api/internal/request/word.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
type AddWordRequest struct {
|
||||||
|
Word string `json:"word" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReviewAnswerRequest struct {
|
||||||
|
RecordID int64 `json:"record_id" binding:"required"`
|
||||||
|
Answer string `json:"answer" binding:"required"`
|
||||||
|
Mode string `json:"mode" binding:"required"` // spelling, en2cn, cn2en
|
||||||
|
}
|
||||||
10
memora-api/internal/response/word.go
Normal file
10
memora-api/internal/response/word.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "memora-api/internal/model"
|
||||||
|
|
||||||
|
type ReviewResult struct {
|
||||||
|
Word *model.Word `json:"word"`
|
||||||
|
Correct bool `json:"correct"`
|
||||||
|
Answer string `json:"answer"`
|
||||||
|
CorrectAns string `json:"correct_ans,omitempty"`
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@ import (
|
|||||||
|
|
||||||
"memora-api/internal/config"
|
"memora-api/internal/config"
|
||||||
"memora-api/internal/model"
|
"memora-api/internal/model"
|
||||||
|
"memora-api/internal/request"
|
||||||
|
"memora-api/internal/response"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@@ -359,7 +361,7 @@ func containsAny(def string, ans string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提交复习答案
|
// 提交复习答案
|
||||||
func (s *WordService) SubmitReviewAnswer(req model.ReviewAnswerRequest) (*model.ReviewResult, error) {
|
func (s *WordService) SubmitReviewAnswer(req request.ReviewAnswerRequest) (*response.ReviewResult, error) {
|
||||||
var record model.MemoryRecord
|
var record model.MemoryRecord
|
||||||
if err := s.db.Preload("Word").Where("id = ?", req.RecordID).First(&record).Error; err != nil {
|
if err := s.db.Preload("Word").Where("id = ?", req.RecordID).First(&record).Error; err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -387,7 +389,7 @@ func (s *WordService) SubmitReviewAnswer(req model.ReviewAnswerRequest) (*model.
|
|||||||
// 更新记忆记录
|
// 更新记忆记录
|
||||||
s.updateMemoryRecord(record.WordID, correct)
|
s.updateMemoryRecord(record.WordID, correct)
|
||||||
|
|
||||||
return &model.ReviewResult{
|
return &response.ReviewResult{
|
||||||
Word: word,
|
Word: word,
|
||||||
Correct: correct,
|
Correct: correct,
|
||||||
Answer: req.Answer,
|
Answer: req.Answer,
|
||||||
@@ -422,9 +424,9 @@ func (s *WordService) GetStatistics() (map[string]interface{}, error) {
|
|||||||
s.db.Model(&model.MemoryRecord{}).Where("last_reviewed_at >= ?", time.Now().Format("2006-01-02")).Count(&todayReviewed)
|
s.db.Model(&model.MemoryRecord{}).Where("last_reviewed_at >= ?", time.Now().Format("2006-01-02")).Count(&todayReviewed)
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"total_words": totalWords,
|
"total_words": totalWords,
|
||||||
"mastered_words": masteredWords,
|
"mastered_words": masteredWords,
|
||||||
"need_review": needReview,
|
"need_review": needReview,
|
||||||
"today_reviewed": todayReviewed,
|
"today_reviewed": todayReviewed,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user