158 lines
4.5 KiB
Go
158 lines
4.5 KiB
Go
|
|
package handler
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"net/http"
|
|||
|
|
"strconv"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"soul-api/internal/database"
|
|||
|
|
"soul-api/internal/model"
|
|||
|
|
|
|||
|
|
"github.com/gin-gonic/gin"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// UserAddressesGet GET /api/user/addresses
|
|||
|
|
func UserAddressesGet(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true, "data": []interface{}{}})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserAddressesPost POST /api/user/addresses
|
|||
|
|
func UserAddressesPost(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserAddressesByID GET/PUT/DELETE /api/user/addresses/:id
|
|||
|
|
func UserAddressesByID(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserCheckPurchased GET /api/user/check-purchased
|
|||
|
|
func UserCheckPurchased(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserProfileGet GET /api/user/profile
|
|||
|
|
func UserProfileGet(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserProfilePost POST /api/user/profile
|
|||
|
|
func UserProfilePost(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserPurchaseStatus GET /api/user/purchase-status
|
|||
|
|
func UserPurchaseStatus(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserReadingProgressGet GET /api/user/reading-progress
|
|||
|
|
func UserReadingProgressGet(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserReadingProgressPost POST /api/user/reading-progress
|
|||
|
|
func UserReadingProgressPost(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserTrackGet GET /api/user/track?userId=&limit= 从 user_tracks 表查(GORM)
|
|||
|
|
func UserTrackGet(c *gin.Context) {
|
|||
|
|
userId := c.Query("userId")
|
|||
|
|
phone := c.Query("phone")
|
|||
|
|
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
|
|||
|
|
if limit < 1 || limit > 100 {
|
|||
|
|
limit = 50
|
|||
|
|
}
|
|||
|
|
if userId == "" && phone == "" {
|
|||
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "需要用户ID或手机号"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
db := database.DB()
|
|||
|
|
if userId == "" && phone != "" {
|
|||
|
|
var u model.User
|
|||
|
|
if err := db.Where("phone = ?", phone).First(&u).Error; err != nil {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": false, "error": "用户不存在"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
userId = u.ID
|
|||
|
|
}
|
|||
|
|
var tracks []model.UserTrack
|
|||
|
|
if err := db.Where("user_id = ?", userId).Order("created_at DESC").Limit(limit).Find(&tracks).Error; err != nil {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true, "tracks": []interface{}{}, "stats": gin.H{}, "total": 0})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
stats := make(map[string]int)
|
|||
|
|
formatted := make([]gin.H, 0, len(tracks))
|
|||
|
|
for _, t := range tracks {
|
|||
|
|
stats[t.Action]++
|
|||
|
|
target := ""
|
|||
|
|
if t.Target != nil {
|
|||
|
|
target = *t.Target
|
|||
|
|
}
|
|||
|
|
if t.ChapterID != nil && target == "" {
|
|||
|
|
target = *t.ChapterID
|
|||
|
|
}
|
|||
|
|
formatted = append(formatted, gin.H{
|
|||
|
|
"id": t.ID, "action": t.Action, "target": target, "chapterTitle": t.ChapterID,
|
|||
|
|
"createdAt": t.CreatedAt,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true, "tracks": formatted, "stats": stats, "total": len(formatted)})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserTrackPost POST /api/user/track 记录行为(GORM)
|
|||
|
|
func UserTrackPost(c *gin.Context) {
|
|||
|
|
var body struct {
|
|||
|
|
UserID string `json:"userId"`
|
|||
|
|
Phone string `json:"phone"`
|
|||
|
|
Action string `json:"action"`
|
|||
|
|
Target string `json:"target"`
|
|||
|
|
ExtraData interface{} `json:"extraData"`
|
|||
|
|
}
|
|||
|
|
if err := c.ShouldBindJSON(&body); err != nil {
|
|||
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "请求体无效"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
if body.UserID == "" && body.Phone == "" {
|
|||
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "需要用户ID或手机号"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
if body.Action == "" {
|
|||
|
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "行为类型不能为空"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
db := database.DB()
|
|||
|
|
userId := body.UserID
|
|||
|
|
if userId == "" {
|
|||
|
|
var u model.User
|
|||
|
|
if err := db.Where("phone = ?", body.Phone).First(&u).Error; err != nil {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": false, "error": "用户不存在"})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
userId = u.ID
|
|||
|
|
}
|
|||
|
|
trackID := fmt.Sprintf("track_%d", time.Now().UnixNano()%100000000)
|
|||
|
|
chID := body.Target
|
|||
|
|
if body.Action == "view_chapter" {
|
|||
|
|
chID = body.Target
|
|||
|
|
}
|
|||
|
|
t := model.UserTrack{
|
|||
|
|
ID: trackID, UserID: userId, Action: body.Action, Target: &body.Target,
|
|||
|
|
}
|
|||
|
|
if body.Target != "" {
|
|||
|
|
t.ChapterID = &chID
|
|||
|
|
}
|
|||
|
|
if err := db.Create(&t).Error; err != nil {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true, "trackId": trackID, "message": "行为记录成功"})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UserUpdate POST /api/user/update
|
|||
|
|
func UserUpdate(c *gin.Context) {
|
|||
|
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
|||
|
|
}
|