feat: 完整重构小程序匹配功能 + 修复UI对齐 + 文章数据API

主要更新:
1. 按H5网页端完全重构匹配功能(match页面)
   - 4种匹配类型: 创业合伙/资源对接/导师顾问/团队招募
   - 资源对接等类型弹出手机号/微信号输入框
   - 去掉重新匹配按钮,改为返回按钮

2. 修复所有卡片对齐和宽度问题
   - 目录页附录卡片居中
   - 首页阅读进度卡片满宽度
   - 我的页面菜单卡片对齐
   - 推广中心分享卡片统一宽度

3. 修复目录页图标和文字对齐
   - section-icon固定40rpx宽高
   - section-title与图标垂直居中

4. 更新真实完整文章标题(62篇)
   - 从book目录读取真实markdown文件名
   - 替换之前的简化标题

5. 新增文章数据API
   - /api/db/chapters - 获取完整书籍结构
   - 支持按ID获取单篇文章内容
This commit is contained in:
卡若
2026-01-21 15:49:12 +08:00
parent 1ee25e3dab
commit b60edb3d47
197 changed files with 34430 additions and 7345 deletions

View File

@@ -0,0 +1,251 @@
/**
* Soul创业实验 - 目录页
* 开发: 卡若
* 技术支持: 存客宝
* 数据: 完整真实文章标题
*/
const app = getApp()
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: '附录1Soul派对房精选对话' },
{ id: 'appendix-2', title: '附录2创业者自检清单' },
{ id: 'appendix-3', title: '附录3本书提到的工具和资源' }
]
},
onLoad() {
this.setData({
statusBarHeight: app.globalData.statusBarHeight,
navBarHeight: app.globalData.navBarHeight
})
this.updateUserStatus()
},
onShow() {
// 设置TabBar选中状态
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().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
})
},
// 跳转到阅读页
goToRead(e) {
const id = e.currentTarget.dataset.id
wx.navigateTo({ url: `/pages/read/read?id=${id}` })
},
// 检查是否已购买
hasPurchased(sectionId) {
if (this.data.hasFullBook) return true
return this.data.purchasedSections.includes(sectionId)
},
// 返回首页
goBack() {
wx.switchTab({ url: '/pages/index/index' })
}
})

View File

@@ -0,0 +1,6 @@
{
"usingComponents": {},
"enablePullDownRefresh": false,
"backgroundTextStyle": "light",
"backgroundColor": "#000000"
}

View File

@@ -0,0 +1,125 @@
<!--pages/chapters/chapters.wxml-->
<!--Soul创业实验 - 目录页 1:1还原Web版本-->
<view class="page page-transition">
<!-- 自定义导航栏 -->
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
<view class="nav-content">
<view class="nav-title brand-color">目录</view>
</view>
</view>
<!-- 导航栏占位 -->
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
<!-- 书籍信息卡 -->
<view class="book-info-card card-gradient">
<view class="book-icon">
<view class="book-icon-inner">📚</view>
</view>
<view class="book-info">
<text class="book-title">一场SOUL的创业实验场</text>
<text class="book-subtitle">来自Soul派对房的真实商业故事</text>
</view>
<view class="book-count">
<text class="count-value brand-color">{{totalSections}}</text>
<text class="count-label">章节</text>
</view>
</view>
<!-- 目录内容 -->
<view class="chapters-content">
<!-- 序言 -->
<view class="chapter-item" bindtap="goToRead" data-id="preface">
<view class="item-left">
<view class="item-icon icon-brand">📖</view>
<text class="item-title">序言为什么我每天早上6点在Soul开播?</text>
</view>
<view class="item-right">
<text class="tag tag-free">免费</text>
<text class="item-arrow">→</text>
</view>
</view>
<!-- 篇章列表 -->
<view class="part-list">
<view class="part-item" wx:for="{{bookData}}" wx:key="id">
<!-- 篇章标题 -->
<view class="part-header" bindtap="togglePart" data-id="{{item.id}}">
<view class="part-left">
<view class="part-icon">{{item.number}}</view>
<view class="part-info">
<text class="part-title">{{item.title}}</text>
<text class="part-subtitle">{{item.subtitle}}</text>
</view>
</view>
<view class="part-right">
<text class="part-count">{{item.chapters.length}}章</text>
<text class="part-arrow {{expandedPart === item.id ? 'arrow-down' : ''}}">→</text>
</view>
</view>
<!-- 章节列表 - 展开时显示 -->
<block wx:if="{{expandedPart === item.id}}">
<view class="chapters-list">
<block wx:for="{{item.chapters}}" wx:key="id" wx:for-item="chapter">
<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-left">
<view class="section-icon {{section.isFree || hasFullBook || purchasedSections.indexOf(section.id) > -1 ? 'icon-unlocked' : 'icon-locked'}}">
<text wx:if="{{section.isFree || hasFullBook || purchasedSections.indexOf(section.id) > -1}}">🔓</text>
<text wx:else>🔒</text>
</view>
<text class="section-title {{section.isFree || hasFullBook || purchasedSections.indexOf(section.id) > -1 ? '' : 'text-muted'}}">
{{section.id}} {{section.title}}
</text>
</view>
<view class="section-right">
<text wx:if="{{section.isFree}}" class="tag tag-free">免费</text>
<text wx:elif="{{hasFullBook || purchasedSections.indexOf(section.id) > -1}}" class="text-brand text-xs">已购</text>
<text wx:else class="text-muted text-xs">¥{{section.price}}</text>
<text class="section-arrow">→</text>
</view>
</view>
</block>
</view>
</block>
</view>
</block>
</view>
</view>
<!-- 尾声 -->
<view class="chapter-item" bindtap="goToRead" data-id="epilogue">
<view class="item-left">
<view class="item-icon icon-brand">📖</view>
<text class="item-title">尾声|这本书的真实目的</text>
</view>
<view class="item-right">
<text class="tag tag-free">免费</text>
<text class="item-arrow">→</text>
</view>
</view>
<!-- 附录 -->
<view class="appendix-card card">
<text class="appendix-title">附录</text>
<view class="appendix-list">
<view
class="appendix-item"
wx:for="{{appendixList}}"
wx:key="id"
bindtap="goToRead"
data-id="{{item.id}}"
>
<text class="appendix-text">{{item.title}}</text>
<text class="appendix-arrow">→</text>
</view>
</view>
</view>
</view>
<!-- 底部留白 -->
<view class="bottom-space"></view>
</view>

View File

@@ -0,0 +1,439 @@
/**
* Soul创业实验 - 目录页样式
* 1:1还原Web版本UI
*/
.page {
min-height: 100vh;
background: #000000;
padding-bottom: 200rpx;
}
/* ===== 自定义导航栏 ===== */
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(40rpx);
-webkit-backdrop-filter: blur(40rpx);
border-bottom: 1rpx solid rgba(255, 255, 255, 0.05);
}
.nav-content {
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
}
.nav-title {
font-size: 36rpx;
font-weight: 600;
}
.brand-color {
color: #00CED1;
}
.nav-placeholder {
width: 100%;
}
/* ===== 书籍信息卡 ===== */
.book-info-card {
display: flex;
align-items: center;
gap: 24rpx;
margin: 32rpx;
padding: 32rpx;
}
.card-gradient {
background: linear-gradient(135deg, #1c1c1e 0%, #2c2c2e 100%);
border-radius: 32rpx;
border: 2rpx solid rgba(0, 206, 209, 0.2);
}
.book-icon {
width: 96rpx;
height: 96rpx;
border-radius: 24rpx;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.book-icon-inner {
font-size: 48rpx;
}
.book-info {
flex: 1;
min-width: 0;
}
.book-title {
font-size: 32rpx;
font-weight: 600;
color: #ffffff;
display: block;
margin-bottom: 4rpx;
}
.book-subtitle {
font-size: 22rpx;
color: rgba(255, 255, 255, 0.4);
}
.book-count {
text-align: right;
}
.count-value {
font-size: 40rpx;
font-weight: 700;
display: block;
}
.count-label {
font-size: 20rpx;
color: rgba(255, 255, 255, 0.4);
}
/* ===== 目录内容 ===== */
.chapters-content {
padding: 0 32rpx;
width: 100%;
box-sizing: border-box;
}
/* ===== 章节项 ===== */
.chapter-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
background: #1c1c1e;
border-radius: 24rpx;
border: 2rpx solid rgba(255, 255, 255, 0.05);
margin-bottom: 24rpx;
}
.chapter-item:active {
background: #2c2c2e;
}
.item-left {
display: flex;
align-items: center;
gap: 24rpx;
flex: 1;
min-width: 0;
}
.item-icon {
width: 64rpx;
height: 64rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
flex-shrink: 0;
}
.icon-brand {
background: rgba(0, 206, 209, 0.2);
}
.item-title {
font-size: 28rpx;
font-weight: 500;
color: #ffffff;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.item-right {
display: flex;
align-items: center;
gap: 16rpx;
flex-shrink: 0;
}
.item-arrow {
font-size: 32rpx;
color: rgba(255, 255, 255, 0.4);
}
/* ===== 标签 ===== */
.tag {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 22rpx;
padding: 6rpx 16rpx;
min-width: 80rpx;
border-radius: 8rpx;
box-sizing: border-box;
text-align: center;
}
.tag-free {
background: rgba(0, 206, 209, 0.1);
color: #00CED1;
}
.text-brand {
color: #00CED1;
}
.text-muted {
color: rgba(255, 255, 255, 0.4);
}
.text-xs {
font-size: 22rpx;
}
/* ===== 篇章列表 ===== */
.part-list {
margin-bottom: 24rpx;
}
.part-item {
margin-bottom: 24rpx;
}
.part-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
background: #1c1c1e;
border-radius: 24rpx;
border: 2rpx solid rgba(255, 255, 255, 0.05);
}
.part-header:active {
background: #2c2c2e;
}
.part-left {
display: flex;
align-items: center;
gap: 24rpx;
}
.part-icon {
width: 64rpx;
height: 64rpx;
border-radius: 16rpx;
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 700;
color: #ffffff;
flex-shrink: 0;
}
.part-info {
display: flex;
flex-direction: column;
}
.part-title {
font-size: 28rpx;
font-weight: 600;
color: #ffffff;
}
.part-subtitle {
font-size: 20rpx;
color: rgba(255, 255, 255, 0.4);
margin-top: 4rpx;
}
.part-right {
display: flex;
align-items: center;
gap: 16rpx;
}
.part-count {
font-size: 22rpx;
color: rgba(255, 255, 255, 0.4);
}
.part-arrow {
font-size: 32rpx;
color: rgba(255, 255, 255, 0.4);
transition: transform 0.3s ease;
}
.arrow-down {
transform: rotate(90deg);
}
/* ===== 章节组 ===== */
.chapters-list {
margin-top: 16rpx;
margin-left: 16rpx;
}
.chapter-group {
background: rgba(28, 28, 30, 0.5);
border-radius: 16rpx;
border: 2rpx solid rgba(255, 255, 255, 0.05);
overflow: hidden;
margin-bottom: 8rpx;
}
.chapter-header {
padding: 16rpx 24rpx;
font-size: 24rpx;
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
border-bottom: 1rpx solid rgba(255, 255, 255, 0.05);
}
.section-list {
/* 小节列表 */
}
.section-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 20rpx 24rpx;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.05);
}
.section-item:last-child {
border-bottom: none;
}
.section-item:active {
background: rgba(255, 255, 255, 0.05);
}
.section-left {
display: flex;
flex-direction: row;
align-items: center;
gap: 16rpx;
flex: 1;
min-width: 0;
}
.section-icon {
width: 40rpx;
height: 40rpx;
min-width: 40rpx;
font-size: 26rpx;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.icon-unlocked {
color: #00CED1;
}
.icon-locked {
color: rgba(255, 255, 255, 0.4);
}
.section-title {
font-size: 26rpx;
color: #ffffff;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 40rpx;
flex: 1;
vertical-align: middle;
}
.section-right {
display: flex;
align-items: center;
gap: 16rpx;
flex-shrink: 0;
margin-left: 16rpx;
}
.section-arrow {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.3);
}
/* ===== 附录 ===== */
.card {
background: #1c1c1e;
border-radius: 24rpx;
border: 2rpx solid rgba(255, 255, 255, 0.05);
margin: 0 0 24rpx 0;
width: 100%;
box-sizing: border-box;
}
.appendix-card {
padding: 24rpx;
width: 100%;
box-sizing: border-box;
margin: 0 0 24rpx 0;
}
.appendix-title {
font-size: 24rpx;
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
display: block;
margin-bottom: 16rpx;
}
.appendix-list {
/* 附录列表 */
}
.appendix-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16rpx 0;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.05);
}
.appendix-item:last-child {
border-bottom: none;
}
.appendix-item:active {
opacity: 0.7;
}
.appendix-text {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.8);
}
.appendix-arrow {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.3);
}
/* ===== 底部留白 ===== */
.bottom-space {
height: 40rpx;
}