2026-01-21 15:49:12 +08:00
|
|
|
|
const app = getApp()
|
|
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
|
data: {
|
|
|
|
|
|
statusBarHeight: 44,
|
|
|
|
|
|
navBarHeight: 88,
|
|
|
|
|
|
totalSections: 62,
|
2026-02-02 18:16:15 +08:00
|
|
|
|
bookData: [],
|
2026-01-21 15:49:12 +08:00
|
|
|
|
expandedPart: 'part-1',
|
2026-02-02 18:16:15 +08:00
|
|
|
|
hasFullBook: false,
|
|
|
|
|
|
purchasedSections: [],
|
2026-01-21 15:49:12 +08:00
|
|
|
|
appendixList: [
|
|
|
|
|
|
{ id: 'appendix-1', title: '附录1|Soul派对房精选对话' },
|
|
|
|
|
|
{ id: 'appendix-2', title: '附录2|创业者自检清单' },
|
|
|
|
|
|
{ id: 'appendix-3', title: '附录3|本书提到的工具和资源' }
|
|
|
|
|
|
]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onLoad() {
|
2026-02-02 18:16:15 +08:00
|
|
|
|
this.setNavBarHeight()
|
|
|
|
|
|
this.loadChapters()
|
|
|
|
|
|
this.syncUserStatus()
|
2026-01-21 15:49:12 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShow() {
|
2026-02-02 18:16:15 +08:00
|
|
|
|
if (typeof this.getTabBar === 'function' && this.getTabBar()) this.getTabBar().setData({ selected: 1 })
|
|
|
|
|
|
this.setNavBarHeight()
|
|
|
|
|
|
this.syncUserStatus()
|
2026-01-21 15:49:12 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-02 18:16:15 +08:00
|
|
|
|
setNavBarHeight() {
|
|
|
|
|
|
const statusBarHeight = app.globalData.statusBarHeight || 44
|
|
|
|
|
|
const navBarHeight = app.globalData.navBarHeight || (statusBarHeight + 44)
|
|
|
|
|
|
this.setData({ statusBarHeight, navBarHeight })
|
2026-01-21 15:49:12 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-02 18:16:15 +08:00
|
|
|
|
loadChapters() {
|
|
|
|
|
|
app.request('/api/book/all-chapters').then((res) => {
|
|
|
|
|
|
if (res && res.data && Array.isArray(res.data)) {
|
|
|
|
|
|
const bookData = this.normalizeBookData(res.data)
|
|
|
|
|
|
const totalSections = res.totalSections || res.total || res.data.length || 62
|
|
|
|
|
|
this.setData({ bookData, totalSections })
|
|
|
|
|
|
} else if (res && res.chapters) {
|
|
|
|
|
|
const bookData = this.normalizeBookData(res.chapters)
|
|
|
|
|
|
this.setData({ bookData, totalSections: res.chapters.length || 62 })
|
|
|
|
|
|
}
|
|
|
|
|
|
}).catch(() => {})
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
normalizeBookData(list) {
|
|
|
|
|
|
if (!Array.isArray(list) || list.length === 0) return []
|
|
|
|
|
|
const partOrder = ['part-1', 'part-2', 'part-3', 'part-4', 'part-5']
|
|
|
|
|
|
const partTitles = ['真实的人', '真实的行业', '真实的错误', '真实的赚钱', '真实的未来']
|
|
|
|
|
|
const partMap = {}
|
|
|
|
|
|
const subtitles = ['人性观察与社交逻辑', '社会运作的底层规则', '错过机会比失败更贵', '所有行业的杠杆结构', '人与系统的关系']
|
|
|
|
|
|
partOrder.forEach((id, i) => {
|
|
|
|
|
|
partMap[id] = {
|
|
|
|
|
|
id,
|
|
|
|
|
|
number: String(i + 1).padStart(2, '0'),
|
|
|
|
|
|
title: partTitles[i] || ('篇' + (i + 1)),
|
|
|
|
|
|
subtitle: subtitles[i] || '',
|
|
|
|
|
|
chapters: []
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
list.forEach((s) => {
|
|
|
|
|
|
let partId = s.partId || s.part_id
|
|
|
|
|
|
if (!partId && s.id) {
|
|
|
|
|
|
const num = String(s.id).split('.')[0]
|
|
|
|
|
|
partId = partOrder[parseInt(num, 10) - 1] || 'part-1'
|
|
|
|
|
|
}
|
|
|
|
|
|
partId = partId || 'part-1'
|
|
|
|
|
|
if (!partMap[partId]) partMap[partId] = { id: partId, number: '99', title: '其他', subtitle: '', chapters: [] }
|
|
|
|
|
|
const chId = s.chapterId || s.chapter_id || 'ch1'
|
|
|
|
|
|
let ch = partMap[partId].chapters.find(c => c.id === chId)
|
|
|
|
|
|
if (!ch) {
|
|
|
|
|
|
ch = { id: chId, title: s.chapterTitle || s.chapter_title || '章节', sections: [] }
|
|
|
|
|
|
partMap[partId].chapters.push(ch)
|
|
|
|
|
|
}
|
|
|
|
|
|
ch.sections.push({
|
|
|
|
|
|
id: s.id,
|
|
|
|
|
|
title: s.sectionTitle || s.title || s.section_title || '',
|
|
|
|
|
|
isFree: !!s.isFree || !!s.is_free,
|
|
|
|
|
|
price: s.price != null ? s.price : 1
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
const out = partOrder.map(id => partMap[id]).filter(p => p.chapters.length > 0)
|
|
|
|
|
|
out.forEach(p => {
|
|
|
|
|
|
p.sectionCount = p.chapters.reduce((acc, ch) => acc + (ch.sections ? ch.sections.length : 0), 0)
|
2026-01-21 15:49:12 +08:00
|
|
|
|
})
|
2026-02-02 18:16:15 +08:00
|
|
|
|
if (out.length === 0) {
|
|
|
|
|
|
const sections = list.map(s => ({ id: s.id, title: s.sectionTitle || s.title || s.section_title || '', isFree: !!s.isFree || !!s.is_free, price: s.price != null ? s.price : 1 }))
|
|
|
|
|
|
const single = { id: 'part-1', number: '01', title: '全部', subtitle: '', sectionCount: sections.length, chapters: [{ id: 'ch1', title: '章节', sections }] }
|
|
|
|
|
|
return [single]
|
|
|
|
|
|
}
|
|
|
|
|
|
return out
|
2026-01-21 15:49:12 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-02 18:16:15 +08:00
|
|
|
|
syncUserStatus() {
|
|
|
|
|
|
const { hasFullBook, purchasedSections } = app.globalData
|
|
|
|
|
|
this.setData({ hasFullBook: !!hasFullBook, purchasedSections: purchasedSections || [] })
|
2026-01-21 15:49:12 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
hasPurchased(sectionId) {
|
2026-02-02 18:16:15 +08:00
|
|
|
|
const { hasFullBook, purchasedSections } = app.globalData
|
|
|
|
|
|
if (hasFullBook) return true
|
|
|
|
|
|
return (purchasedSections || []).indexOf(sectionId) >= 0
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
togglePart(e) {
|
|
|
|
|
|
const id = e.currentTarget.dataset.id
|
|
|
|
|
|
const expandedPart = this.data.expandedPart === id ? '' : id
|
|
|
|
|
|
this.setData({ expandedPart })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
goToSearch() {
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/search/search' })
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
goToRead(e) {
|
|
|
|
|
|
const id = e.currentTarget.dataset.id
|
|
|
|
|
|
if (!id) return
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/read/read?id=' + encodeURIComponent(id) })
|
2026-01-21 15:49:12 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-02 18:16:15 +08:00
|
|
|
|
onPullDownRefresh() {
|
|
|
|
|
|
this.loadChapters()
|
|
|
|
|
|
this.syncUserStatus()
|
|
|
|
|
|
wx.stopPullDownRefresh()
|
2026-01-21 15:49:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|