feat: 支持章节通过 mid 进行访问,优化阅读跳转逻辑。新增章节数据结构,包含章节的 mid 信息,提升用户体验。更新 API 以支持通过 mid 查询章节内容,确保兼容性与灵活性。
This commit is contained in:
@@ -6,200 +6,66 @@
|
||||
*/
|
||||
|
||||
const app = getApp()
|
||||
const PART_NUMBERS = { 'part-1': '一', 'part-2': '二', 'part-3': '三', 'part-4': '四', 'part-5': '五' }
|
||||
|
||||
function buildNestedBookData(list) {
|
||||
const parts = {}
|
||||
const appendices = []
|
||||
let epilogueMid = 0
|
||||
let prefaceMid = 0
|
||||
list.forEach(ch => {
|
||||
if (ch.id === 'preface') {
|
||||
prefaceMid = ch.mid || 0
|
||||
return
|
||||
}
|
||||
const section = {
|
||||
id: ch.id,
|
||||
mid: ch.mid || 0,
|
||||
title: ch.sectionTitle || ch.chapterTitle || ch.id,
|
||||
isFree: !!ch.isFree,
|
||||
price: ch.price != null ? Number(ch.price) : 1
|
||||
}
|
||||
if (ch.id === 'epilogue') {
|
||||
epilogueMid = ch.mid || 0
|
||||
return
|
||||
}
|
||||
if ((ch.id || '').startsWith('appendix')) {
|
||||
appendices.push({ id: ch.id, mid: ch.mid || 0, title: ch.sectionTitle || ch.chapterTitle || ch.id })
|
||||
return
|
||||
}
|
||||
if (!ch.partId || ch.id === 'preface') return
|
||||
const pid = ch.partId
|
||||
const cid = ch.chapterId || 'chapter-' + (ch.id || '').split('.')[0]
|
||||
if (!parts[pid]) {
|
||||
parts[pid] = { id: pid, number: PART_NUMBERS[pid] || pid, title: ch.partTitle || pid, subtitle: ch.chapterTitle || '', chapters: {} }
|
||||
}
|
||||
if (!parts[pid].chapters[cid]) {
|
||||
parts[pid].chapters[cid] = { id: cid, title: ch.chapterTitle || cid, sections: [] }
|
||||
}
|
||||
parts[pid].chapters[cid].sections.push(section)
|
||||
})
|
||||
const bookData = Object.values(parts)
|
||||
.sort((a, b) => (a.id || '').localeCompare(b.id || ''))
|
||||
.map(p => ({
|
||||
...p,
|
||||
chapters: Object.values(p.chapters).sort((a, b) => (a.id || '').localeCompare(b.id || ''))
|
||||
}))
|
||||
return { bookData, appendixList: appendices, epilogueMid, prefaceMid }
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 系统信息
|
||||
statusBarHeight: 44,
|
||||
navBarHeight: 88,
|
||||
|
||||
// 用户状态
|
||||
isLoggedIn: false,
|
||||
hasFullBook: false,
|
||||
purchasedSections: [],
|
||||
|
||||
// 书籍数据 - 完整真实标题
|
||||
totalSections: 62,
|
||||
bookData: [
|
||||
{
|
||||
id: 'part-1',
|
||||
number: '一',
|
||||
title: '真实的人',
|
||||
subtitle: '人与人之间的底层逻辑',
|
||||
chapters: [
|
||||
{
|
||||
id: 'chapter-1',
|
||||
title: '第1章|人与人之间的底层逻辑',
|
||||
sections: [
|
||||
{ id: '1.1', title: '荷包:电动车出租的被动收入模式', isFree: true, price: 1 },
|
||||
{ id: '1.2', title: '老墨:资源整合高手的社交方法', isFree: false, price: 1 },
|
||||
{ id: '1.3', title: '笑声背后的MBTI:为什么ENTJ适合做资源,INTP适合做系统', isFree: false, price: 1 },
|
||||
{ id: '1.4', title: '人性的三角结构:利益、情感、价值观', isFree: false, price: 1 },
|
||||
{ id: '1.5', title: '沟通差的问题:为什么你说的别人听不懂', isFree: false, price: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'chapter-2',
|
||||
title: '第2章|人性困境案例',
|
||||
sections: [
|
||||
{ id: '2.1', title: '相亲故事:你以为找的是人,实际是在找模式', isFree: false, price: 1 },
|
||||
{ id: '2.2', title: '找工作迷茫者:为什么简历解决不了人生', isFree: false, price: 1 },
|
||||
{ id: '2.3', title: '撸运费险:小钱困住大脑的真实心理', isFree: false, price: 1 },
|
||||
{ id: '2.4', title: '游戏上瘾的年轻人:不是游戏吸引他,是生活没吸引力', isFree: false, price: 1 },
|
||||
{ id: '2.5', title: '健康焦虑(我的糖尿病经历):疾病是人生的第一次清醒', isFree: false, price: 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-2',
|
||||
number: '二',
|
||||
title: '真实的行业',
|
||||
subtitle: '电商、内容、传统行业解析',
|
||||
chapters: [
|
||||
{
|
||||
id: 'chapter-3',
|
||||
title: '第3章|电商篇',
|
||||
sections: [
|
||||
{ id: '3.1', title: '3000万流水如何跑出来(退税模式解析)', isFree: false, price: 1 },
|
||||
{ id: '3.2', title: '供应链之王 vs 打工人:利润不在前端', isFree: false, price: 1 },
|
||||
{ id: '3.3', title: '社区团购的底层逻辑', isFree: false, price: 1 },
|
||||
{ id: '3.4', title: '跨境电商与退税套利', isFree: false, price: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'chapter-4',
|
||||
title: '第4章|内容商业篇',
|
||||
sections: [
|
||||
{ id: '4.1', title: '旅游号:30天10万粉的真实逻辑', isFree: false, price: 1 },
|
||||
{ id: '4.2', title: '做号工厂:如何让一个号变成一个机器', isFree: false, price: 1 },
|
||||
{ id: '4.3', title: '情绪内容为什么比专业内容更赚钱', isFree: false, price: 1 },
|
||||
{ id: '4.4', title: '猫与宠物号:为什么宠物赛道永不过时', isFree: false, price: 1 },
|
||||
{ id: '4.5', title: '直播间里的三种人:演员、技术工、系统流', isFree: false, price: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'chapter-5',
|
||||
title: '第5章|传统行业篇',
|
||||
sections: [
|
||||
{ id: '5.1', title: '拍卖行抱朴:一天240万的摇号生意', isFree: false, price: 1 },
|
||||
{ id: '5.2', title: '土地拍卖:招拍挂背后的游戏规则', isFree: false, price: 1 },
|
||||
{ id: '5.3', title: '地摊经济数字化:一个月900块的餐车生意', isFree: false, price: 1 },
|
||||
{ id: '5.4', title: '不良资产拍卖:我错过的一个亿佣金', isFree: false, price: 1 },
|
||||
{ id: '5.5', title: '桶装水李总:跟物业合作的轻资产模式', isFree: false, price: 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-3',
|
||||
number: '三',
|
||||
title: '真实的错误',
|
||||
subtitle: '我和别人犯过的错',
|
||||
chapters: [
|
||||
{
|
||||
id: 'chapter-6',
|
||||
title: '第6章|我人生错过的4件大钱',
|
||||
sections: [
|
||||
{ id: '6.1', title: '电商财税窗口:2016年的千万级机会', isFree: false, price: 1 },
|
||||
{ id: '6.2', title: '供应链金融:我不懂的杠杆游戏', isFree: false, price: 1 },
|
||||
{ id: '6.3', title: '内容红利:2019年我为什么没做抖音', isFree: false, price: 1 },
|
||||
{ id: '6.4', title: '数据资产化:我还在观望的未来机会', isFree: false, price: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'chapter-7',
|
||||
title: '第7章|别人犯的错误',
|
||||
sections: [
|
||||
{ id: '7.1', title: '投资房年轻人的迷茫:资金 vs 能力', isFree: false, price: 1 },
|
||||
{ id: '7.2', title: '信息差骗局:永远有人靠卖学习赚钱', isFree: false, price: 1 },
|
||||
{ id: '7.3', title: '在Soul找恋爱但想赚钱的人', isFree: false, price: 1 },
|
||||
{ id: '7.4', title: '创业者的三种死法:冲动、轻信、没结构', isFree: false, price: 1 },
|
||||
{ id: '7.5', title: '人情生意的终点:关系越多亏得越多', isFree: false, price: 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-4',
|
||||
number: '四',
|
||||
title: '真实的赚钱',
|
||||
subtitle: '底层结构与真实案例',
|
||||
chapters: [
|
||||
{
|
||||
id: 'chapter-8',
|
||||
title: '第8章|底层结构',
|
||||
sections: [
|
||||
{ id: '8.1', title: '流量杠杆:抖音、Soul、飞书', isFree: false, price: 1 },
|
||||
{ id: '8.2', title: '价格杠杆:供应链与信息差', isFree: false, price: 1 },
|
||||
{ id: '8.3', title: '时间杠杆:自动化 + AI', isFree: false, price: 1 },
|
||||
{ id: '8.4', title: '情绪杠杆:咨询、婚恋、生意场', isFree: false, price: 1 },
|
||||
{ id: '8.5', title: '社交杠杆:认识谁比你会什么更重要', isFree: false, price: 1 },
|
||||
{ id: '8.6', title: '云阿米巴:分不属于自己的钱', isFree: false, price: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'chapter-9',
|
||||
title: '第9章|我在Soul上亲访的赚钱案例',
|
||||
sections: [
|
||||
{ id: '9.1', title: '游戏账号私域:账号即资产', isFree: false, price: 1 },
|
||||
{ id: '9.2', title: '健康包模式:高复购、高毛利', isFree: false, price: 1 },
|
||||
{ id: '9.3', title: '药物私域:长期关系赛道', isFree: false, price: 1 },
|
||||
{ id: '9.4', title: '残疾机构合作:退税 × AI × 人力成本', isFree: false, price: 1 },
|
||||
{ id: '9.5', title: '私域银行:粉丝即小股东', isFree: false, price: 1 },
|
||||
{ id: '9.6', title: 'Soul派对房:陌生人成交的最快场景', isFree: false, price: 1 },
|
||||
{ id: '9.7', title: '飞书中台:从聊天到成交的流程化体系', isFree: false, price: 1 },
|
||||
{ id: '9.8', title: '餐饮女孩:6万营收、1万利润的死撑生意', isFree: false, price: 1 },
|
||||
{ id: '9.9', title: '电竞生态:从陪玩到签约到酒店的完整链条', isFree: false, price: 1 },
|
||||
{ id: '9.10', title: '淘客大佬:损耗30%的白色通道', isFree: false, price: 1 },
|
||||
{ id: '9.11', title: '蔬菜供应链:农户才是最赚钱的人', isFree: false, price: 1 },
|
||||
{ id: '9.12', title: '美业整合:一个人的公司如何月入十万', isFree: false, price: 1 },
|
||||
{ id: '9.13', title: 'AI工具推广:一个隐藏的高利润赛道', isFree: false, price: 1 },
|
||||
{ id: '9.14', title: '大健康私域:一个月150万的70后', isFree: false, price: 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'part-5',
|
||||
number: '五',
|
||||
title: '真实的社会',
|
||||
subtitle: '未来职业与商业生态',
|
||||
chapters: [
|
||||
{
|
||||
id: 'chapter-10',
|
||||
title: '第10章|未来职业的变化趋势',
|
||||
sections: [
|
||||
{ id: '10.1', title: 'AI时代:哪些工作会消失,哪些会崛起', isFree: false, price: 1 },
|
||||
{ id: '10.2', title: '一人公司:为什么越来越多人选择单干', isFree: false, price: 1 },
|
||||
{ id: '10.3', title: '为什么链接能力会成为第一价值', isFree: false, price: 1 },
|
||||
{ id: '10.4', title: '新型公司:Soul-飞书-线下的三位一体', isFree: false, price: 1 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'chapter-11',
|
||||
title: '第11章|中国社会商业生态的未来',
|
||||
sections: [
|
||||
{ id: '11.1', title: '私域经济:为什么流量越来越贵', isFree: false, price: 1 },
|
||||
{ id: '11.2', title: '银发经济与孤独经济:两个被忽视的万亿市场', isFree: false, price: 1 },
|
||||
{ id: '11.3', title: '流量红利的终局', isFree: false, price: 1 },
|
||||
{ id: '11.4', title: '大模型 + 供应链的组合拳', isFree: false, price: 1 },
|
||||
{ id: '11.5', title: '社会分层的最终逻辑', isFree: false, price: 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
// 展开状态
|
||||
expandedPart: 'part-1',
|
||||
|
||||
// 附录
|
||||
appendixList: [
|
||||
{ id: 'appendix-1', title: '附录1|Soul派对房精选对话' },
|
||||
{ id: 'appendix-2', title: '附录2|创业者自检清单' },
|
||||
{ id: 'appendix-3', title: '附录3|本书提到的工具和资源' }
|
||||
]
|
||||
bookData: [],
|
||||
expandedPart: null,
|
||||
appendixList: [],
|
||||
epilogueMid: 0,
|
||||
prefaceMid: 0
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -208,10 +74,44 @@ Page({
|
||||
navBarHeight: app.globalData.navBarHeight
|
||||
})
|
||||
this.updateUserStatus()
|
||||
this.loadAndEnrichBookData()
|
||||
},
|
||||
|
||||
async loadAndEnrichBookData() {
|
||||
try {
|
||||
let list = app.globalData.bookData || []
|
||||
if (!list.length) {
|
||||
const res = await app.request('/api/miniprogram/book/all-chapters')
|
||||
if (res?.data) {
|
||||
list = res.data
|
||||
app.globalData.bookData = list
|
||||
}
|
||||
}
|
||||
if (!list.length) {
|
||||
this.setData({ bookData: [], appendixList: [] })
|
||||
return
|
||||
}
|
||||
const { bookData, appendixList, epilogueMid, prefaceMid } = buildNestedBookData(list)
|
||||
const firstPartId = bookData[0]?.id || null
|
||||
this.setData({
|
||||
bookData,
|
||||
appendixList,
|
||||
epilogueMid,
|
||||
prefaceMid,
|
||||
totalSections: list.length,
|
||||
expandedPart: firstPartId || this.data.expandedPart
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('[Chapters] 加载目录失败:', e)
|
||||
this.setData({ bookData: [], appendixList: [] })
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 设置TabBar选中状态
|
||||
this.updateUserStatus()
|
||||
if (!app.globalData.bookData?.length) {
|
||||
this.loadAndEnrichBookData()
|
||||
}
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
const tabBar = this.getTabBar()
|
||||
if (tabBar.updateSelected) {
|
||||
@@ -220,7 +120,6 @@ Page({
|
||||
tabBar.setData({ selected: 1 })
|
||||
}
|
||||
}
|
||||
this.updateUserStatus()
|
||||
},
|
||||
|
||||
// 更新用户状态
|
||||
@@ -237,10 +136,11 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到阅读页
|
||||
goToRead(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
wx.navigateTo({ url: `/pages/read/read?id=${id}` })
|
||||
const mid = e.currentTarget.dataset.mid || app.getSectionMid(id)
|
||||
const q = mid ? `mid=${mid}` : `id=${id}`
|
||||
wx.navigateTo({ url: `/pages/read/read?${q}` })
|
||||
},
|
||||
|
||||
// 检查是否已购买
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<!-- 目录内容 -->
|
||||
<view class="chapters-content">
|
||||
<!-- 序言 -->
|
||||
<view class="chapter-item" bindtap="goToRead" data-id="preface">
|
||||
<view class="chapter-item" bindtap="goToRead" data-id="preface" data-mid="{{prefaceMid}}">
|
||||
<view class="item-left">
|
||||
<view class="item-icon icon-brand">📖</view>
|
||||
<text class="item-title">序言|为什么我每天早上6点在Soul开播?</text>
|
||||
@@ -71,7 +71,7 @@
|
||||
<view class="chapter-header">{{chapter.title}}</view>
|
||||
<view class="section-list">
|
||||
<block wx:for="{{chapter.sections}}" wx:key="id" wx:for-item="section">
|
||||
<view class="section-item" bindtap="goToRead" data-id="{{section.id}}">
|
||||
<view class="section-item" bindtap="goToRead" data-id="{{section.id}}" data-mid="{{section.mid}}">
|
||||
<view class="section-left">
|
||||
<text class="section-lock {{section.isFree || hasFullBook || purchasedSections.indexOf(section.id) > -1 ? 'lock-open' : 'lock-closed'}}">{{section.isFree || hasFullBook || purchasedSections.indexOf(section.id) > -1 ? '○' : '●'}}</text>
|
||||
<text class="section-title {{section.isFree || hasFullBook || purchasedSections.indexOf(section.id) > -1 ? '' : 'text-muted'}}">{{section.id}} {{section.title}}</text>
|
||||
@@ -92,7 +92,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 尾声 -->
|
||||
<view class="chapter-item" bindtap="goToRead" data-id="epilogue">
|
||||
<view class="chapter-item" bindtap="goToRead" data-id="epilogue" data-mid="{{epilogueMid}}">
|
||||
<view class="item-left">
|
||||
<view class="item-icon icon-brand">📖</view>
|
||||
<text class="item-title">尾声|这本书的真实目的</text>
|
||||
@@ -113,6 +113,7 @@
|
||||
wx:key="id"
|
||||
bindtap="goToRead"
|
||||
data-id="{{item.id}}"
|
||||
data-mid="{{item.mid}}"
|
||||
>
|
||||
<text class="appendix-text">{{item.title}}</text>
|
||||
<text class="appendix-arrow">→</text>
|
||||
|
||||
Reference in New Issue
Block a user