2026-03-07 22:58:43 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Soul创业派对 - 目录页
|
|
|
|
|
|
* 开发: 卡若
|
|
|
|
|
|
* 技术支持: 存客宝
|
|
|
|
|
|
* 数据: 完整真实文章标题
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
const app = getApp()
|
|
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
|
data: {
|
|
|
|
|
|
// 系统信息
|
|
|
|
|
|
statusBarHeight: 44,
|
|
|
|
|
|
navBarHeight: 88,
|
|
|
|
|
|
|
|
|
|
|
|
// 用户状态
|
|
|
|
|
|
isLoggedIn: false,
|
|
|
|
|
|
hasFullBook: false,
|
|
|
|
|
|
purchasedSections: [],
|
|
|
|
|
|
|
2026-03-08 08:00:39 +08:00
|
|
|
|
// 书籍数据:以后台内容管理为准,仅用接口 /api/miniprogram/book/all-chapters 返回的数据
|
|
|
|
|
|
totalSections: 0,
|
|
|
|
|
|
bookData: [],
|
2026-03-07 22:58:43 +08:00
|
|
|
|
|
|
|
|
|
|
// 展开状态:默认不展开任何篇章,直接显示目录
|
|
|
|
|
|
expandedPart: null,
|
|
|
|
|
|
|
|
|
|
|
|
// 附录
|
|
|
|
|
|
appendixList: [
|
|
|
|
|
|
{ id: 'appendix-1', title: '附录1|Soul派对房精选对话' },
|
|
|
|
|
|
{ id: 'appendix-2', title: '附录2|创业者自检清单' },
|
|
|
|
|
|
{ id: 'appendix-3', title: '附录3|本书提到的工具和资源' }
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
|
|
// 每日新增章节
|
|
|
|
|
|
dailyChapters: []
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onLoad() {
|
|
|
|
|
|
wx.showShareMenu({ withShareTimeline: true })
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
statusBarHeight: app.globalData.statusBarHeight,
|
|
|
|
|
|
navBarHeight: app.globalData.navBarHeight
|
|
|
|
|
|
})
|
|
|
|
|
|
this.updateUserStatus()
|
|
|
|
|
|
this.loadChaptersOnce()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 固定模块(序言、尾声、附录)不参与中间篇章
|
|
|
|
|
|
_isFixedPart(pt) {
|
|
|
|
|
|
if (!pt) return false
|
|
|
|
|
|
const p = String(pt).toLowerCase().replace(/[_\s||]/g, '')
|
|
|
|
|
|
return p.includes('序言') || p.includes('尾声') || p.includes('附录')
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-08 08:00:39 +08:00
|
|
|
|
// 一次请求拉取全量目录,以后台内容管理为准;同时更新 totalSections / bookData / dailyChapters
|
2026-03-07 22:58:43 +08:00
|
|
|
|
async loadChaptersOnce() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await app.request({ url: '/api/miniprogram/book/all-chapters', silent: true })
|
|
|
|
|
|
const rows = (res && res.data) || (res && res.chapters) || []
|
|
|
|
|
|
|
2026-03-08 08:00:39 +08:00
|
|
|
|
// 无数据时清空目录,避免展示旧数据
|
|
|
|
|
|
if (rows.length === 0) {
|
|
|
|
|
|
app.globalData.bookData = []
|
|
|
|
|
|
wx.setStorageSync('bookData', [])
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
bookData: [],
|
|
|
|
|
|
totalSections: 0,
|
|
|
|
|
|
dailyChapters: [],
|
|
|
|
|
|
expandedPart: null
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-07 22:58:43 +08:00
|
|
|
|
const totalSections = res.total ?? rows.length
|
2026-03-08 08:00:39 +08:00
|
|
|
|
app.globalData.bookData = rows
|
|
|
|
|
|
wx.setStorageSync('bookData', rows)
|
2026-03-07 22:58:43 +08:00
|
|
|
|
|
2026-03-08 08:00:39 +08:00
|
|
|
|
// bookData:过滤序言/尾声/附录,按 part 聚合,篇章顺序按 sort_order 与后台一致(含「2026每日派对干货」等)
|
2026-03-07 22:58:43 +08:00
|
|
|
|
const filtered = rows.filter(r => !this._isFixedPart(r.partTitle || r.part_title))
|
|
|
|
|
|
const partMap = new Map()
|
|
|
|
|
|
const numbers = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二']
|
|
|
|
|
|
filtered.forEach((r) => {
|
|
|
|
|
|
const pid = r.partId || r.part_id || 'part-1'
|
|
|
|
|
|
const cid = r.chapterId || r.chapter_id || 'chapter-1'
|
2026-03-08 08:00:39 +08:00
|
|
|
|
const sortOrder = r.sectionOrder ?? r.sort_order ?? 999999
|
2026-03-07 22:58:43 +08:00
|
|
|
|
if (!partMap.has(pid)) {
|
|
|
|
|
|
const partIdx = partMap.size
|
|
|
|
|
|
partMap.set(pid, {
|
|
|
|
|
|
id: pid,
|
|
|
|
|
|
number: numbers[partIdx] || String(partIdx + 1),
|
|
|
|
|
|
title: r.partTitle || r.part_title || '未分类',
|
|
|
|
|
|
subtitle: r.chapterTitle || r.chapter_title || '',
|
2026-03-08 08:00:39 +08:00
|
|
|
|
chapters: new Map(),
|
|
|
|
|
|
minSortOrder: sortOrder
|
2026-03-07 22:58:43 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
const part = partMap.get(pid)
|
2026-03-08 08:00:39 +08:00
|
|
|
|
if (sortOrder < part.minSortOrder) part.minSortOrder = sortOrder
|
2026-03-07 22:58:43 +08:00
|
|
|
|
if (!part.chapters.has(cid)) {
|
|
|
|
|
|
part.chapters.set(cid, {
|
|
|
|
|
|
id: cid,
|
|
|
|
|
|
title: r.chapterTitle || r.chapter_title || '未分类',
|
|
|
|
|
|
sections: []
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
const ch = part.chapters.get(cid)
|
|
|
|
|
|
ch.sections.push({
|
|
|
|
|
|
id: r.id,
|
|
|
|
|
|
mid: r.mid ?? r.MID ?? 0,
|
|
|
|
|
|
title: r.sectionTitle || r.section_title || r.title || '',
|
|
|
|
|
|
isFree: r.isFree === true || (r.price !== undefined && r.price === 0),
|
|
|
|
|
|
price: r.price ?? 1,
|
|
|
|
|
|
isNew: r.isNew === true || r.is_new === true
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
2026-03-08 08:00:39 +08:00
|
|
|
|
const partList = Array.from(partMap.values())
|
|
|
|
|
|
partList.sort((a, b) => (a.minSortOrder ?? 999999) - (b.minSortOrder ?? 999999))
|
|
|
|
|
|
const bookData = partList.map((p, idx) => ({
|
|
|
|
|
|
id: p.id,
|
|
|
|
|
|
number: numbers[idx] || String(idx + 1),
|
|
|
|
|
|
title: p.title,
|
|
|
|
|
|
subtitle: p.subtitle,
|
2026-03-07 22:58:43 +08:00
|
|
|
|
chapters: Array.from(p.chapters.values())
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
const baseSort = 62
|
|
|
|
|
|
const daily = rows
|
|
|
|
|
|
.filter(r => (r.sectionOrder ?? r.sort_order ?? 0) > baseSort)
|
|
|
|
|
|
.sort((a, b) => new Date(b.updatedAt || b.updated_at || 0) - new Date(a.updatedAt || a.updated_at || 0))
|
|
|
|
|
|
.slice(0, 20)
|
|
|
|
|
|
.map(c => {
|
|
|
|
|
|
const d = new Date(c.updatedAt || c.updated_at || Date.now())
|
|
|
|
|
|
return {
|
|
|
|
|
|
id: c.id,
|
|
|
|
|
|
mid: c.mid ?? c.MID ?? 0,
|
|
|
|
|
|
title: c.section_title || c.title || c.sectionTitle,
|
|
|
|
|
|
price: c.price ?? 1,
|
|
|
|
|
|
dateStr: `${d.getMonth() + 1}/${d.getDate()}`
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
bookData,
|
|
|
|
|
|
totalSections,
|
|
|
|
|
|
dailyChapters: daily,
|
|
|
|
|
|
expandedPart: this.data.expandedPart
|
|
|
|
|
|
})
|
2026-03-08 08:00:39 +08:00
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.log('[Chapters] 加载目录失败:', e)
|
|
|
|
|
|
this.setData({ bookData: [], totalSections: 0 })
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onPullDownRefresh() {
|
|
|
|
|
|
this.loadChaptersOnce().then(() => wx.stopPullDownRefresh()).catch(() => wx.stopPullDownRefresh())
|
2026-03-07 22:58:43 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShow() {
|
|
|
|
|
|
// 设置TabBar选中状态
|
|
|
|
|
|
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
|
|
|
|
|
const tabBar = this.getTabBar()
|
|
|
|
|
|
if (tabBar.updateSelected) {
|
|
|
|
|
|
tabBar.updateSelected()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
tabBar.setData({ selected: 1 })
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
this.updateUserStatus()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 更新用户状态
|
|
|
|
|
|
updateUserStatus() {
|
|
|
|
|
|
const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
|
|
|
|
|
|
this.setData({ isLoggedIn, hasFullBook, purchasedSections })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 切换展开状态
|
|
|
|
|
|
togglePart(e) {
|
|
|
|
|
|
const partId = e.currentTarget.dataset.id
|
|
|
|
|
|
this.setData({
|
|
|
|
|
|
expandedPart: this.data.expandedPart === partId ? null : partId
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到阅读页(优先传 mid,与分享逻辑一致)
|
|
|
|
|
|
goToRead(e) {
|
|
|
|
|
|
const id = e.currentTarget.dataset.id
|
|
|
|
|
|
const mid = e.currentTarget.dataset.mid || app.getSectionMid(id)
|
|
|
|
|
|
const q = mid ? `mid=${mid}` : `id=${id}`
|
|
|
|
|
|
wx.navigateTo({ url: `/pages/read/read?${q}` })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已购买
|
|
|
|
|
|
hasPurchased(sectionId) {
|
|
|
|
|
|
if (this.data.hasFullBook) return true
|
|
|
|
|
|
return this.data.purchasedSections.includes(sectionId)
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 返回首页
|
|
|
|
|
|
goBack() {
|
|
|
|
|
|
wx.switchTab({ url: '/pages/index/index' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 跳转到搜索页
|
|
|
|
|
|
goToSearch() {
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/search/search' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShareAppMessage() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: 'Soul创业派对 - 目录',
|
|
|
|
|
|
path: ref ? `/pages/chapters/chapters?ref=${ref}` : '/pages/chapters/chapters'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShareTimeline() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
|
|
|
|
|
return { title: 'Soul创业派对 - 真实商业故事', query: ref ? `ref=${ref}` : '' }
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|