更新小程序,新增VIP会员状态管理功能,优化章节解锁逻辑,支持VIP用户访问增值内容。调整用户详情页面,增加VIP相关字段和功能,提升用户体验。更新会议记录,反映最新讨论内容。

This commit is contained in:
Alex-larget
2026-03-10 11:04:34 +08:00
parent 30ebdb5ac7
commit 05ac60dc7e
60 changed files with 8387 additions and 1583 deletions

View File

@@ -171,18 +171,43 @@ func UserCheckPurchased(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"isPurchased": true, "reason": "has_vip"}})
return
}
hasFullBook := user.HasFullBook != nil && *user.HasFullBook
if hasFullBook {
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"isPurchased": true, "reason": "has_full_book"}})
return
}
if type_ == "fullbook" {
// 9.9 买断:永久权益,写入 users.has_full_book兜底再查订单
if user.HasFullBook != nil && *user.HasFullBook {
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"isPurchased": true, "reason": "has_full_book"}})
return
}
var count int64
db.Model(&model.Order{}).Where("user_id = ? AND product_type = ? AND status = ?", userId, "fullbook", "paid").Count(&count)
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"isPurchased": count > 0, "reason": map[bool]string{true: "fullbook_order_exists"}[count > 0]}})
return
}
if type_ == "section" && productId != "" {
// 章节:需要区分普通版/增值版
var ch model.Chapter
// 不加载 content避免大字段
_ = db.Select("id", "is_free", "price", "edition_standard", "edition_premium").Where("id = ?", productId).First(&ch).Error
// 免费章节:直接可读
if ch.ID != "" {
if (ch.IsFree != nil && *ch.IsFree) || (ch.Price != nil && *ch.Price == 0) {
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"isPurchased": true, "reason": "free_section"}})
return
}
}
isPremium := ch.ID != "" && ch.EditionPremium != nil && *ch.EditionPremium
// 默认普通版:未明确标记增值版时,按普通版处理
isStandard := !isPremium
// 普通版:买断可读;增值版:买断不包含
if isStandard {
if user.HasFullBook != nil && *user.HasFullBook {
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"isPurchased": true, "reason": "has_full_book"}})
return
}
}
var count int64
db.Model(&model.Order{}).Where("user_id = ? AND product_type = ? AND product_id = ? AND status = ?", userId, "section", productId, "paid").Count(&count)
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"isPurchased": count > 0, "reason": map[bool]string{true: "section_order_exists"}[count > 0]}})
@@ -382,11 +407,8 @@ func UserPurchaseStatus(c *gin.Context) {
if user.PendingEarnings != nil {
pendingEarnings = *user.PendingEarnings
}
// 超级VIP管理端开通与 check-purchased 一致,视为全章可读
// 9.9 买断:仅表示“普通版买断”,不等同 VIP增值版仍需 VIP 或单章购买)
hasFullBook := user.HasFullBook != nil && *user.HasFullBook
if !hasFullBook && user.IsVip != nil && *user.IsVip && user.VipExpireDate != nil && user.VipExpireDate.After(time.Now()) {
hasFullBook = true
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{
"hasFullBook": hasFullBook,
"purchasedSections": purchasedSections,