更新管理端迁移Mycontent-temp的菜单与布局规范,确保主导航收敛并优化隐藏页面入口。新增相关会议记录与文档,反映团队讨论的最新决策与实施建议。
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"soul-api/internal/database"
|
||||
"soul-api/internal/model"
|
||||
@@ -109,8 +111,61 @@ func getFreeChapterIDs(db *gorm.DB) map[string]bool {
|
||||
return ids
|
||||
}
|
||||
|
||||
// checkUserChapterAccess 判断 userId 是否有权读取 chapterID(VIP / 全书购买 / 单章购买)
|
||||
// isPremium=true 表示增值版,fullbook 买断不含增值版
|
||||
func checkUserChapterAccess(db *gorm.DB, userID, chapterID string, isPremium bool) bool {
|
||||
if userID == "" {
|
||||
return false
|
||||
}
|
||||
// VIP:is_vip=1 且未过期
|
||||
var u model.User
|
||||
if err := db.Select("id", "is_vip", "vip_expire_date", "has_full_book").Where("id = ?", userID).First(&u).Error; err != nil {
|
||||
return false
|
||||
}
|
||||
if u.IsVip != nil && *u.IsVip && u.VipExpireDate != nil && u.VipExpireDate.After(time.Now()) {
|
||||
return true
|
||||
}
|
||||
// 全书买断(不含增值版)
|
||||
if !isPremium && u.HasFullBook != nil && *u.HasFullBook {
|
||||
return true
|
||||
}
|
||||
// 全书订单(兜底)
|
||||
if !isPremium {
|
||||
var cnt int64
|
||||
db.Model(&model.Order{}).Where("user_id = ? AND product_type = 'fullbook' AND status = 'paid'", userID).Count(&cnt)
|
||||
if cnt > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// 单章购买
|
||||
var cnt int64
|
||||
db.Model(&model.Order{}).Where(
|
||||
"user_id = ? AND product_type = 'section' AND product_id = ? AND status = 'paid'",
|
||||
userID, chapterID,
|
||||
).Count(&cnt)
|
||||
return cnt > 0
|
||||
}
|
||||
|
||||
// previewContent 取内容的前 20%(最多前 200 个字符),并追加省略提示
|
||||
func previewContent(content string) string {
|
||||
total := utf8.RuneCountInString(content)
|
||||
if total == 0 {
|
||||
return ""
|
||||
}
|
||||
limit := total / 5
|
||||
if limit < 100 {
|
||||
limit = 100
|
||||
}
|
||||
if limit > total {
|
||||
limit = total
|
||||
}
|
||||
runes := []rune(content)
|
||||
return string(runes[:limit]) + "\n\n……(购买后阅读完整内容)"
|
||||
}
|
||||
|
||||
// findChapterAndRespond 按条件查章节并返回统一格式
|
||||
// 免费判断优先级:system_config.free_chapters / chapter_config.freeChapters > chapters.is_free/price
|
||||
// 付费章节:若请求携带 userId 且有购买权限则返回完整 content,否则返回 previewContent
|
||||
func findChapterAndRespond(c *gin.Context, whereFn func(*gorm.DB) *gorm.DB) {
|
||||
var ch model.Chapter
|
||||
db := database.DB()
|
||||
@@ -122,30 +177,43 @@ func findChapterAndRespond(c *gin.Context, whereFn func(*gorm.DB) *gorm.DB) {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
isFreeFromConfig := getFreeChapterIDs(db)[ch.ID]
|
||||
isFree := isFreeFromConfig
|
||||
if !isFree && ch.IsFree != nil && *ch.IsFree {
|
||||
isFree = true
|
||||
}
|
||||
if !isFree && ch.Price != nil && *ch.Price == 0 {
|
||||
isFree = true
|
||||
}
|
||||
|
||||
// 确定返回的 content:免费直接返回,付费须校验购买权限
|
||||
userID := c.Query("userId")
|
||||
isPremium := ch.EditionPremium != nil && *ch.EditionPremium
|
||||
var returnContent string
|
||||
if isFree {
|
||||
returnContent = ch.Content
|
||||
} else if checkUserChapterAccess(db, userID, ch.ID, isPremium) {
|
||||
returnContent = ch.Content
|
||||
} else {
|
||||
returnContent = previewContent(ch.Content)
|
||||
}
|
||||
|
||||
out := gin.H{
|
||||
"success": true,
|
||||
"data": ch,
|
||||
"content": ch.Content,
|
||||
"content": returnContent,
|
||||
"chapterTitle": ch.ChapterTitle,
|
||||
"partTitle": ch.PartTitle,
|
||||
"id": ch.ID,
|
||||
"mid": ch.MID,
|
||||
"sectionTitle": ch.SectionTitle,
|
||||
"isFree": isFree,
|
||||
}
|
||||
isFreeFromConfig := getFreeChapterIDs(db)[ch.ID]
|
||||
if isFreeFromConfig {
|
||||
out["isFree"] = true
|
||||
out["price"] = float64(0)
|
||||
} else {
|
||||
if ch.IsFree != nil {
|
||||
out["isFree"] = *ch.IsFree
|
||||
}
|
||||
if ch.Price != nil {
|
||||
out["price"] = *ch.Price
|
||||
if *ch.Price == 0 {
|
||||
out["isFree"] = true
|
||||
}
|
||||
}
|
||||
} else if ch.Price != nil {
|
||||
out["price"] = *ch.Price
|
||||
}
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user