重构小程序图标组件,替换传统 emoji 为 SVG 图标,提升视觉一致性和可维护性。更新多个页面以使用新图标组件,优化用户界面体验。同时,调整了数据加载逻辑,确保更高效的状态管理和用户交互。

This commit is contained in:
Alex-larget
2026-03-18 16:00:57 +08:00
parent 46f94a9c81
commit c55e54efbd
62 changed files with 2033 additions and 1270 deletions

View File

@@ -223,6 +223,10 @@ func WarmBookPartsCache() {
}
// BookAllChapters GET /api/book/all-chapters 返回所有章节(列表,来自 chapters 表)
//
// Deprecated: 小程序已迁移至 book/parts + chapters-by-part + book/statsid↔mid 从各接口响应积累。
// 保留以兼容旧版/管理端,计划后续下线。
//
// 排序须与管理端 PUT /api/db/book action=reorder 一致:按 sort_order 升序,同序按 id
// 免费判断system_config.free_chapters / chapter_config.freeChapters 优先于 chapters.is_free
// 支持 excludeFixed=1排除序言、尾声、附录目录页固定模块不参与中间篇章
@@ -398,6 +402,29 @@ func BookChaptersByPart(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true, "data": list})
}
// getOrderedChapterList 获取按 sort_order+id 排序的章节列表(复用 all-chapters 缓存)
func getOrderedChapterList() []model.Chapter {
var list []model.Chapter
if cache.Get(context.Background(), cache.KeyAllChapters("default"), &list) && len(list) > 0 {
return list
}
allChaptersCache.mu.RLock()
if allChaptersCache.key == "default" && time.Now().Before(allChaptersCache.expires) && len(allChaptersCache.data) > 0 {
list = allChaptersCache.data
allChaptersCache.mu.RUnlock()
return list
}
allChaptersCache.mu.RUnlock()
db := database.DB()
if err := db.Model(&model.Chapter{}).Select(allChaptersSelectCols).
Order("COALESCE(sort_order, 999999) ASC, id ASC").
Find(&list).Error; err != nil || len(list) == 0 {
return nil
}
sortChaptersByNaturalID(list)
return list
}
// BookChapterByMID GET /api/book/chapter/by-mid/:mid 按自增主键 mid 查询(新链接推荐)
func BookChapterByMID(c *gin.Context) {
midStr := c.Param("mid")
@@ -618,6 +645,38 @@ func findChapterAndRespond(c *gin.Context, whereFn func(*gorm.DB) *gorm.DB) {
"sectionTitle": ch.SectionTitle,
"isFree": isFree,
}
// 文章详情内直接输出上一篇/下一篇,省去单独请求
if list := getOrderedChapterList(); len(list) > 0 {
idx := -1
for i, item := range list {
if item.ID == ch.ID {
idx = i
break
}
}
if idx >= 0 {
toItem := func(c *model.Chapter) gin.H {
if c == nil {
return nil
}
t := c.SectionTitle
if t == "" {
t = c.ChapterTitle
}
return gin.H{"id": c.ID, "mid": c.MID, "title": t}
}
if idx > 0 {
out["prev"] = toItem(&list[idx-1])
} else {
out["prev"] = nil
}
if idx < len(list)-1 {
out["next"] = toItem(&list[idx+1])
} else {
out["next"] = nil
}
}
}
if isFreeFromConfig {
out["price"] = float64(0)
} else if ch.Price != nil {