Update evolution indices and enhance user experience in mini program
- Added new entries for content ranking algorithm adjustments and cross-platform reuse in the evolution indices for backend, team, and mini program development. - Improved user interface elements in the mini program, including the addition of a hidden settings entry and refined guidance for profile modifications. - Enhanced reading statistics display with formatted numbers for better clarity and user engagement. - Updated reading tracker logic to prevent duplicate duration accumulation and ensure accurate reporting of reading progress.
This commit is contained in:
@@ -540,14 +540,12 @@ func DBUsersList(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "user": nil})
|
||||
return
|
||||
}
|
||||
// 填充 hasFullBook(含 is_vip 或 orders)
|
||||
// 填充 hasFullBook(含 orders、is_vip、手动设置的 has_full_book)
|
||||
var cnt int64
|
||||
db.Model(&model.Order{}).Where("user_id = ? AND (status = ? OR status = ?) AND (product_type = ? OR product_type = ?)",
|
||||
id, "paid", "completed", "fullbook", "vip").Count(&cnt)
|
||||
user.HasFullBook = ptrBool(cnt > 0)
|
||||
if user.IsVip != nil && *user.IsVip {
|
||||
user.HasFullBook = ptrBool(true)
|
||||
}
|
||||
hasFull := cnt > 0 || (user.IsVip != nil && *user.IsVip) || (user.HasFullBook != nil && *user.HasFullBook)
|
||||
user.HasFullBook = ptrBool(hasFull)
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "user": user})
|
||||
return
|
||||
}
|
||||
@@ -670,11 +668,14 @@ func DBUsersList(c *gin.Context) {
|
||||
// 填充每个用户的实时计算字段
|
||||
for i := range users {
|
||||
uid := users[i].ID
|
||||
// 购买状态(含手动设置的 VIP:is_vip=1 且 vip_expire_date>NOW)
|
||||
// 购买状态(含订单、is_vip、手动设置的 has_full_book)
|
||||
hasFull := hasFullBookMap[uid]
|
||||
if users[i].IsVip != nil && *users[i].IsVip && users[i].VipExpireDate != nil && users[i].VipExpireDate.After(time.Now()) {
|
||||
hasFull = true
|
||||
}
|
||||
if users[i].HasFullBook != nil && *users[i].HasFullBook {
|
||||
hasFull = true
|
||||
}
|
||||
users[i].HasFullBook = ptrBool(hasFull)
|
||||
users[i].PurchasedSectionCount = sectionCountMap[uid]
|
||||
// 分销收益
|
||||
|
||||
@@ -451,20 +451,44 @@ func UserReadingProgressGet(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": out})
|
||||
}
|
||||
|
||||
// parseDuration 从 JSON 解析 duration,兼容数字与字符串(防止客户端传字符串导致累加异常)
|
||||
func parseDuration(v interface{}) int {
|
||||
if v == nil {
|
||||
return 0
|
||||
}
|
||||
switch x := v.(type) {
|
||||
case float64:
|
||||
return int(x)
|
||||
case int:
|
||||
return x
|
||||
case int64:
|
||||
return int(x)
|
||||
case string:
|
||||
n, _ := strconv.Atoi(x)
|
||||
return n
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// UserReadingProgressPost POST /api/user/reading-progress
|
||||
func UserReadingProgressPost(c *gin.Context) {
|
||||
var body struct {
|
||||
UserID string `json:"userId" binding:"required"`
|
||||
SectionID string `json:"sectionId" binding:"required"`
|
||||
Progress int `json:"progress"`
|
||||
Duration int `json:"duration"`
|
||||
Status string `json:"status"`
|
||||
CompletedAt *string `json:"completedAt"`
|
||||
UserID string `json:"userId" binding:"required"`
|
||||
SectionID string `json:"sectionId" binding:"required"`
|
||||
Progress int `json:"progress"`
|
||||
Duration interface{} `json:"duration"` // 兼容 int/float64/string,防止字符串导致累加异常
|
||||
Status string `json:"status"`
|
||||
CompletedAt *string `json:"completedAt"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "缺少必要参数"})
|
||||
return
|
||||
}
|
||||
duration := parseDuration(body.Duration)
|
||||
if duration < 0 {
|
||||
duration = 0
|
||||
}
|
||||
db := database.DB()
|
||||
now := time.Now()
|
||||
var existing model.ReadingProgress
|
||||
@@ -474,7 +498,7 @@ func UserReadingProgressPost(c *gin.Context) {
|
||||
if body.Progress > newProgress {
|
||||
newProgress = body.Progress
|
||||
}
|
||||
newDuration := existing.Duration + body.Duration
|
||||
newDuration := existing.Duration + duration
|
||||
newStatus := body.Status
|
||||
if newStatus == "" {
|
||||
newStatus = "reading"
|
||||
@@ -501,7 +525,7 @@ func UserReadingProgressPost(c *gin.Context) {
|
||||
completedAt = &t
|
||||
}
|
||||
db.Create(&model.ReadingProgress{
|
||||
UserID: body.UserID, SectionID: body.SectionID, Progress: body.Progress, Duration: body.Duration,
|
||||
UserID: body.UserID, SectionID: body.SectionID, Progress: body.Progress, Duration: duration,
|
||||
Status: status, CompletedAt: completedAt, FirstOpenAt: &now, LastOpenAt: &now,
|
||||
})
|
||||
}
|
||||
@@ -681,6 +705,10 @@ func UserDashboardStats(c *gin.Context) {
|
||||
if totalReadSeconds > 0 && totalReadMinutes == 0 {
|
||||
totalReadMinutes = 1
|
||||
}
|
||||
// 异常数据保护:历史 bug 导致累加错误可能产生超大值, cap 到 99999 分钟(约 69 天)
|
||||
if totalReadMinutes > 99999 {
|
||||
totalReadMinutes = 99999
|
||||
}
|
||||
|
||||
// 3. 批量查 chapters 获取真实标题与 mid
|
||||
chapterMap := make(map[string]model.Chapter)
|
||||
|
||||
Reference in New Issue
Block a user