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:
51
miniprogram/pages/about/about.js
Normal file
51
miniprogram/pages/about/about.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Soul创业实验 - 关于作者页
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
author: {
|
||||
name: '卡若',
|
||||
avatar: 'K',
|
||||
title: 'Soul派对房主理人',
|
||||
bio: '每天早上6点到9点,在Soul派对房分享真实的创业故事。专注私域运营与项目变现,用"云阿米巴"模式帮助创业者构建可持续的商业体系。',
|
||||
stats: [
|
||||
{ label: '派对房分享', value: '500+' },
|
||||
{ label: '直播天数', value: '365+' },
|
||||
{ label: '商业案例', value: '62+' }
|
||||
],
|
||||
contact: {
|
||||
wechat: '28533368',
|
||||
phone: '15880802661'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight
|
||||
})
|
||||
},
|
||||
|
||||
// 复制微信号
|
||||
copyWechat() {
|
||||
wx.setClipboardData({
|
||||
data: this.data.author.contact.wechat,
|
||||
success: () => wx.showToast({ title: '微信号已复制', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
// 拨打电话
|
||||
callPhone() {
|
||||
wx.makePhoneCall({
|
||||
phoneNumber: this.data.author.contact.phone
|
||||
})
|
||||
},
|
||||
|
||||
// 返回
|
||||
goBack() {
|
||||
wx.navigateBack()
|
||||
}
|
||||
})
|
||||
4
miniprogram/pages/about/about.json
Normal file
4
miniprogram/pages/about/about.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
45
miniprogram/pages/about/about.wxml
Normal file
45
miniprogram/pages/about/about.wxml
Normal file
@@ -0,0 +1,45 @@
|
||||
<!--关于作者-->
|
||||
<view class="page">
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-back" bindtap="goBack">←</view>
|
||||
<text class="nav-title">关于作者</text>
|
||||
<view class="nav-placeholder"></view>
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<view class="content">
|
||||
<view class="author-card">
|
||||
<view class="author-avatar">{{author.avatar}}</view>
|
||||
<text class="author-name">{{author.name}}</text>
|
||||
<text class="author-title">{{author.title}}</text>
|
||||
<text class="author-bio">{{author.bio}}</text>
|
||||
|
||||
<view class="stats-row">
|
||||
<view class="stat-item" wx:for="{{author.stats}}" wx:key="label">
|
||||
<text class="stat-value">{{item.value}}</text>
|
||||
<text class="stat-label">{{item.label}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="contact-card">
|
||||
<text class="card-title">联系作者</text>
|
||||
<view class="contact-item" bindtap="copyWechat">
|
||||
<text class="contact-icon">💬</text>
|
||||
<view class="contact-info">
|
||||
<text class="contact-label">微信</text>
|
||||
<text class="contact-value">{{author.contact.wechat}}</text>
|
||||
</view>
|
||||
<text class="contact-btn">复制</text>
|
||||
</view>
|
||||
<view class="contact-item" bindtap="callPhone">
|
||||
<text class="contact-icon">📱</text>
|
||||
<view class="contact-info">
|
||||
<text class="contact-label">电话</text>
|
||||
<text class="contact-value">{{author.contact.phone}}</text>
|
||||
</view>
|
||||
<text class="contact-btn">拨打</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
24
miniprogram/pages/about/about.wxss
Normal file
24
miniprogram/pages/about/about.wxss
Normal file
@@ -0,0 +1,24 @@
|
||||
.page { min-height: 100vh; background: #000; }
|
||||
.nav-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(0,0,0,0.9); backdrop-filter: blur(40rpx); display: flex; align-items: center; justify-content: space-between; padding: 0 32rpx; height: 88rpx; }
|
||||
.nav-back { width: 72rpx; height: 72rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 32rpx; color: #fff; }
|
||||
.nav-title { font-size: 36rpx; font-weight: 600; color: #00CED1; }
|
||||
.nav-placeholder { width: 72rpx; }
|
||||
.content { padding: 32rpx; }
|
||||
.author-card { background: linear-gradient(135deg, #1c1c1e 0%, #2c2c2e 100%); border-radius: 32rpx; padding: 48rpx; text-align: center; margin-bottom: 24rpx; border: 2rpx solid rgba(0,206,209,0.2); }
|
||||
.author-avatar { width: 160rpx; height: 160rpx; border-radius: 50%; background: linear-gradient(135deg, #00CED1, #20B2AA); display: flex; align-items: center; justify-content: center; margin: 0 auto 24rpx; font-size: 64rpx; color: #fff; font-weight: 700; border: 4rpx solid rgba(0,206,209,0.3); }
|
||||
.author-name { font-size: 40rpx; font-weight: 700; color: #fff; display: block; margin-bottom: 8rpx; }
|
||||
.author-title { font-size: 26rpx; color: #00CED1; display: block; margin-bottom: 24rpx; }
|
||||
.author-bio { font-size: 26rpx; color: rgba(255,255,255,0.7); line-height: 1.8; display: block; margin-bottom: 32rpx; }
|
||||
.stats-row { display: flex; justify-content: space-around; padding-top: 32rpx; border-top: 2rpx solid rgba(255,255,255,0.1); }
|
||||
.stat-item { text-align: center; }
|
||||
.stat-value { font-size: 36rpx; font-weight: 700; color: #00CED1; display: block; }
|
||||
.stat-label { font-size: 22rpx; color: rgba(255,255,255,0.5); }
|
||||
.contact-card { background: #1c1c1e; border-radius: 32rpx; padding: 32rpx; }
|
||||
.card-title { font-size: 28rpx; font-weight: 600; color: #fff; display: block; margin-bottom: 24rpx; }
|
||||
.contact-item { display: flex; align-items: center; gap: 24rpx; padding: 24rpx; background: rgba(255,255,255,0.05); border-radius: 16rpx; margin-bottom: 16rpx; }
|
||||
.contact-item:last-child { margin-bottom: 0; }
|
||||
.contact-icon { font-size: 40rpx; }
|
||||
.contact-info { flex: 1; }
|
||||
.contact-label { font-size: 22rpx; color: rgba(255,255,255,0.5); display: block; }
|
||||
.contact-value { font-size: 28rpx; color: #fff; }
|
||||
.contact-btn { padding: 12rpx 24rpx; background: rgba(0,206,209,0.2); color: #00CED1; font-size: 24rpx; border-radius: 16rpx; }
|
||||
251
miniprogram/pages/chapters/chapters.js
Normal file
251
miniprogram/pages/chapters/chapters.js
Normal 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: '附录1|Soul派对房精选对话' },
|
||||
{ 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' })
|
||||
}
|
||||
})
|
||||
6
miniprogram/pages/chapters/chapters.json
Normal file
6
miniprogram/pages/chapters/chapters.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundTextStyle": "light",
|
||||
"backgroundColor": "#000000"
|
||||
}
|
||||
125
miniprogram/pages/chapters/chapters.wxml
Normal file
125
miniprogram/pages/chapters/chapters.wxml
Normal 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>
|
||||
439
miniprogram/pages/chapters/chapters.wxss
Normal file
439
miniprogram/pages/chapters/chapters.wxss
Normal 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;
|
||||
}
|
||||
@@ -1,232 +1,139 @@
|
||||
// pages/index/index.js
|
||||
/**
|
||||
* Soul创业实验 - 首页
|
||||
* 开发: 卡若
|
||||
* 技术支持: 存客宝
|
||||
*/
|
||||
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
bookStats: {
|
||||
chapters: 64,
|
||||
words: '15万',
|
||||
readers: '1.5万'
|
||||
// 系统信息
|
||||
statusBarHeight: 44,
|
||||
navBarHeight: 88,
|
||||
|
||||
// 用户信息
|
||||
isLoggedIn: false,
|
||||
hasFullBook: false,
|
||||
purchasedCount: 0,
|
||||
|
||||
// 书籍数据
|
||||
totalSections: 62,
|
||||
bookData: [],
|
||||
|
||||
// 推荐章节
|
||||
featuredSections: [
|
||||
{ id: '1.1', title: '荷包:电动车出租的被动收入模式', tag: '免费', tagClass: 'tag-free', part: '真实的人' },
|
||||
{ id: '3.1', title: '3000万流水如何跑出来', tag: '热门', tagClass: 'tag-pink', part: '真实的行业' },
|
||||
{ id: '8.1', title: '流量杠杆:抖音、Soul、飞书', tag: '推荐', tagClass: 'tag-purple', part: '真实的赚钱' }
|
||||
],
|
||||
|
||||
// 最新章节
|
||||
latestSection: {
|
||||
id: '9.14',
|
||||
title: '大健康私域:一个月150万的70后',
|
||||
part: '真实的赚钱'
|
||||
},
|
||||
allChapters: [],
|
||||
|
||||
// 内容概览
|
||||
partsList: [
|
||||
{ id: 'part-1', number: '一', title: '真实的人', subtitle: '人与人之间的底层逻辑' },
|
||||
{ id: 'part-2', number: '二', title: '真实的行业', subtitle: '电商、内容、传统行业解析' },
|
||||
{ id: 'part-3', number: '三', title: '真实的错误', subtitle: '我和别人犯过的错' },
|
||||
{ id: 'part-4', number: '四', title: '真实的赚钱', subtitle: '底层结构与真实案例' },
|
||||
{ id: 'part-5', number: '五', title: '真实的社会', subtitle: '未来职业与商业生态' }
|
||||
],
|
||||
|
||||
// 加载状态
|
||||
loading: true
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadAllChapters()
|
||||
// 获取系统信息
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight,
|
||||
navBarHeight: app.globalData.navBarHeight
|
||||
})
|
||||
|
||||
// 初始化数据
|
||||
this.initData()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 每次显示时刷新数据
|
||||
this.refreshData()
|
||||
},
|
||||
|
||||
// 加载所有章节
|
||||
loadAllChapters() {
|
||||
wx.showLoading({ title: '加载中...', mask: true })
|
||||
|
||||
// 先尝试读取本地生成的章节数据
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/book/all-chapters`,
|
||||
method: 'GET',
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.chapters) {
|
||||
this.setData({
|
||||
allChapters: res.data.chapters,
|
||||
bookStats: {
|
||||
chapters: res.data.total || res.data.chapters.length,
|
||||
words: '15万',
|
||||
readers: '1.5万'
|
||||
},
|
||||
loading: false
|
||||
})
|
||||
// 缓存到本地
|
||||
wx.setStorageSync('allChapters', res.data.chapters)
|
||||
} else {
|
||||
this.loadLocalChapters()
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 使用本地缓存数据
|
||||
this.loadLocalChapters()
|
||||
},
|
||||
complete: () => {
|
||||
wx.hideLoading()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 加载本地章节数据(离线模式)
|
||||
loadLocalChapters() {
|
||||
// 尝试从缓存读取
|
||||
const cached = wx.getStorageSync('allChapters')
|
||||
if (cached && cached.length > 0) {
|
||||
this.setData({
|
||||
allChapters: cached,
|
||||
bookStats: {
|
||||
chapters: cached.length,
|
||||
words: '15万',
|
||||
readers: '1.5万'
|
||||
},
|
||||
loading: false
|
||||
})
|
||||
return
|
||||
// 设置TabBar选中状态
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
this.getTabBar().setData({ selected: 0 })
|
||||
}
|
||||
|
||||
// 更新用户状态
|
||||
this.updateUserStatus()
|
||||
},
|
||||
|
||||
// 如果没有缓存,使用模拟数据
|
||||
const mockChapters = [
|
||||
{ index: 1, id: 'preface', title: '序言|为什么我每天早上6点在Soul开播?', updateTime: '今天', words: 3200, partTitle: '序言' },
|
||||
{ index: 2, id: 'ch1-1', title: '1.1 荷包:电动车出租的被动收入模式', updateTime: '今天', words: 4500, partTitle: '第一篇|真实的人' },
|
||||
{ index: 3, id: 'ch1-2', title: '1.2 老墨:资源整合高手的社交方法', updateTime: '今天', words: 3800, partTitle: '第一篇|真实的人' },
|
||||
]
|
||||
// 初始化数据
|
||||
async initData() {
|
||||
this.setData({ loading: true })
|
||||
|
||||
try {
|
||||
// 获取书籍数据
|
||||
await this.loadBookData()
|
||||
} catch (e) {
|
||||
console.error('初始化失败:', e)
|
||||
} finally {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 加载书籍数据
|
||||
async loadBookData() {
|
||||
try {
|
||||
const res = await app.request('/api/book/all-chapters')
|
||||
if (res && res.data) {
|
||||
this.setData({
|
||||
bookData: res.data,
|
||||
totalSections: res.totalSections || 62
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载书籍数据失败:', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 更新用户状态
|
||||
updateUserStatus() {
|
||||
const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
|
||||
|
||||
this.setData({
|
||||
allChapters: mockChapters,
|
||||
bookStats: {
|
||||
chapters: mockChapters.length,
|
||||
words: '15万',
|
||||
readers: '1.5万'
|
||||
},
|
||||
loading: false
|
||||
isLoggedIn,
|
||||
hasFullBook,
|
||||
purchasedCount: hasFullBook ? this.data.totalSections : (purchasedSections?.length || 0)
|
||||
})
|
||||
},
|
||||
|
||||
// 刷新数据
|
||||
refreshData() {
|
||||
const bookData = app.globalData.bookData
|
||||
if (bookData) {
|
||||
this.setData({
|
||||
bookStats: {
|
||||
chapters: bookData.totalChapters || 65,
|
||||
words: bookData.totalWords || '12万',
|
||||
readers: bookData.totalReaders || '1.2万'
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 立即阅读(跳转到第一章)
|
||||
readNow() {
|
||||
if (this.data.allChapters.length > 0) {
|
||||
const firstChapter = this.data.allChapters[0]
|
||||
wx.navigateTo({
|
||||
url: `/pages/read/read?id=${firstChapter.id}`
|
||||
})
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '章节加载中...',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 阅读章节
|
||||
readChapter(e) {
|
||||
const chapterId = e.currentTarget.dataset.id
|
||||
wx.navigateTo({
|
||||
url: `/pages/read/read?id=${chapterId}`
|
||||
})
|
||||
},
|
||||
|
||||
// 查看全部章节
|
||||
// 跳转到目录
|
||||
goToChapters() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/chapters/chapters'
|
||||
})
|
||||
wx.switchTab({ url: '/pages/chapters/chapters' })
|
||||
},
|
||||
|
||||
// 购买处理
|
||||
handlePurchase() {
|
||||
// 检查登录状态
|
||||
const userInfo = app.getUserInfo()
|
||||
|
||||
if (!userInfo) {
|
||||
// 未登录,先登录
|
||||
this.showLoginModal()
|
||||
return
|
||||
}
|
||||
|
||||
// 跳转到购买页面
|
||||
wx.navigateTo({
|
||||
url: '/pages/purchase/purchase'
|
||||
})
|
||||
// 跳转到阅读页
|
||||
goToRead(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
wx.navigateTo({ url: `/pages/read/read?id=${id}` })
|
||||
},
|
||||
|
||||
// 显示登录弹窗
|
||||
showLoginModal() {
|
||||
wx.showModal({
|
||||
title: '需要登录',
|
||||
content: '购买前需要先登录账号',
|
||||
confirmText: '立即登录',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.doLogin()
|
||||
}
|
||||
}
|
||||
})
|
||||
// 跳转到匹配页
|
||||
goToMatch() {
|
||||
wx.switchTab({ url: '/pages/match/match' })
|
||||
},
|
||||
|
||||
// 执行登录
|
||||
doLogin() {
|
||||
wx.showLoading({ title: '登录中...', mask: true })
|
||||
|
||||
app.wxLogin((success, user) => {
|
||||
wx.hideLoading()
|
||||
|
||||
if (success) {
|
||||
wx.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
// 登录成功后自动跳转购买
|
||||
setTimeout(() => {
|
||||
this.handlePurchase()
|
||||
}, 1500)
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '登录失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转推广页
|
||||
goToReferral() {
|
||||
wx.switchTab({
|
||||
url: '/pages/my/my?tab=referral'
|
||||
})
|
||||
// 跳转到我的页面
|
||||
goToMy() {
|
||||
wx.switchTab({ url: '/pages/my/my' })
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.loadAllChapters()
|
||||
setTimeout(() => {
|
||||
wx.stopPullDownRefresh()
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
// 分享到微信
|
||||
onShareAppMessage() {
|
||||
const userInfo = app.getUserInfo()
|
||||
const inviteCode = userInfo ? userInfo.inviteCode : ''
|
||||
|
||||
return {
|
||||
title: 'Soul派对·创业实验 - 一场真实的商业探索',
|
||||
path: `/pages/index/index?invite=${inviteCode}`,
|
||||
imageUrl: '/assets/images/share-cover.png'
|
||||
}
|
||||
},
|
||||
|
||||
// 分享到朋友圈
|
||||
onShareTimeline() {
|
||||
const userInfo = app.getUserInfo()
|
||||
const inviteCode = userInfo ? userInfo.inviteCode : ''
|
||||
|
||||
return {
|
||||
title: 'Soul派对·创业实验',
|
||||
query: `invite=${inviteCode}`,
|
||||
imageUrl: '/assets/images/share-cover.png'
|
||||
}
|
||||
async onPullDownRefresh() {
|
||||
await this.initData()
|
||||
this.updateUserStatus()
|
||||
wx.stopPullDownRefresh()
|
||||
}
|
||||
})
|
||||
|
||||
6
miniprogram/pages/index/index.json
Normal file
6
miniprogram/pages/index/index.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": true,
|
||||
"backgroundTextStyle": "light",
|
||||
"backgroundColor": "#000000"
|
||||
}
|
||||
@@ -1,135 +1,144 @@
|
||||
<!--pages/index/index.wxml-->
|
||||
<view class="container page-transition">
|
||||
<!-- 头部装饰光晕 -->
|
||||
<view class="header-glow"></view>
|
||||
|
||||
<!-- 顶部标签 -->
|
||||
<view class="top-tag">
|
||||
<text class="tag-icon">🎉</text>
|
||||
<text class="tag-text">Soul · 派对房</text>
|
||||
</view>
|
||||
|
||||
<!-- 书籍标题区 -->
|
||||
<view class="header-section">
|
||||
<view class="main-title">一场SOUL的</view>
|
||||
<view class="sub-title gradient-text">创业实验场</view>
|
||||
<view class="tagline">来自Soul派对房的真实商业故事</view>
|
||||
<view class="quote-line">"社会不是靠努力,是靠洞察与选择"</view>
|
||||
</view>
|
||||
|
||||
<!-- 数据统计卡片 -->
|
||||
<view class="stats-card card">
|
||||
<view class="stat-item">
|
||||
<view class="stat-value brand-color">¥9.9</view>
|
||||
<view class="stat-label">整本价格</view>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-value">{{bookStats.chapters}}</view>
|
||||
<view class="stat-label">商业案例</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 作者信息 -->
|
||||
<view class="author-bar card">
|
||||
<view class="author-info">
|
||||
<view class="author-avatar">卡</view>
|
||||
<view>
|
||||
<view class="author-label">作者</view>
|
||||
<view class="author-name">卡若</view>
|
||||
<!--Soul创业实验 - 首页 1:1还原Web版本-->
|
||||
<view class="page page-transition">
|
||||
<!-- 自定义导航栏占位 -->
|
||||
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<!-- 顶部区域 -->
|
||||
<view class="header" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="header-content">
|
||||
<view class="logo-section">
|
||||
<view class="logo-icon">
|
||||
<text class="logo-text">S</text>
|
||||
</view>
|
||||
<view class="logo-info">
|
||||
<view class="logo-title">
|
||||
<text class="text-white">Soul</text>
|
||||
<text class="brand-color">创业实验</text>
|
||||
</view>
|
||||
<text class="logo-subtitle">来自派对房的真实故事</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="live-info">
|
||||
<view class="live-label">每日直播</view>
|
||||
<view class="live-time brand-color">06:00-09:00</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 立即阅读按钮 -->
|
||||
<button class="btn-primary main-btn" bindtap="readNow">
|
||||
📖 立即阅读
|
||||
</button>
|
||||
<view class="btn-tip">首章免费 · 部分章节3天后解锁</view>
|
||||
|
||||
<!-- 寄语卡片 -->
|
||||
<view class="quote-card card">
|
||||
<view class="quote-icon">"</view>
|
||||
<view class="quote-content">
|
||||
这不是一本教你成功的鸡汤书。这是我每天早上6点到9点,在Soul派对房和几百个陌生人分享的真实故事。
|
||||
</view>
|
||||
<view class="quote-footer">
|
||||
<view class="footer-avatar">卡</view>
|
||||
<view>
|
||||
<view class="footer-name">卡若</view>
|
||||
<view class="footer-desc">Soul派对房主理人</view>
|
||||
<view class="header-right">
|
||||
<view class="chapter-badge">{{totalSections}}章</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 三个数据展示 -->
|
||||
<view class="highlights-grid">
|
||||
<view class="highlight-item">
|
||||
<view class="h-value">{{bookStats.chapters}}+</view>
|
||||
<view class="h-label">真实案例</view>
|
||||
</view>
|
||||
<view class="highlight-item">
|
||||
<view class="h-value">5</view>
|
||||
<view class="h-label">核心篇章</view>
|
||||
</view>
|
||||
<view class="highlight-item">
|
||||
<view class="h-value">100+</view>
|
||||
<view class="h-label">商业洞察</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 所有章节列表 -->
|
||||
<view class="chapters-section card">
|
||||
<view class="section-title">
|
||||
<text class="title-text">全部章节</text>
|
||||
<text class="chapter-count">共{{allChapters.length}}章</text>
|
||||
</view>
|
||||
|
||||
<view class="chapter-list">
|
||||
<view
|
||||
class="chapter-item"
|
||||
wx:for="{{allChapters}}"
|
||||
wx:key="id"
|
||||
bindtap="readChapter"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="chapter-number">{{item.index}}</view>
|
||||
<view class="chapter-info">
|
||||
<view class="chapter-title">{{item.title}}</view>
|
||||
<view class="chapter-meta">
|
||||
<text class="chapter-time">{{item.updateTime}}</text>
|
||||
<text class="chapter-words">{{item.words}}字</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="chapter-arrow">→</view>
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-bar" bindtap="goToChapters">
|
||||
<view class="search-icon">
|
||||
<view class="search-circle"></view>
|
||||
<view class="search-handle"></view>
|
||||
</view>
|
||||
<text class="search-placeholder">搜索章节...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<view class="main-content">
|
||||
<!-- Banner卡片 - 最新章节 -->
|
||||
<view class="banner-card" bindtap="goToRead" data-id="{{latestSection.id}}">
|
||||
<view class="banner-glow"></view>
|
||||
<view class="banner-tag">最新更新</view>
|
||||
<view class="banner-title">{{latestSection.title}}</view>
|
||||
<view class="banner-part">{{latestSection.part}}</view>
|
||||
<view class="banner-action">
|
||||
<text class="banner-action-text">开始阅读</text>
|
||||
<view class="banner-arrow">→</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 购买提示 -->
|
||||
<view class="purchase-section card">
|
||||
<view class="purchase-title">开启完整阅读</view>
|
||||
<view class="purchase-desc">解锁全部章节,支持作者持续创作</view>
|
||||
<view class="price-info">
|
||||
<text class="price-current">¥9.9</text>
|
||||
<text class="price-tip">起(每天+1元)</text>
|
||||
<!-- 阅读进度卡 -->
|
||||
<view class="progress-card card">
|
||||
<view class="progress-header">
|
||||
<text class="progress-title">我的阅读</text>
|
||||
<text class="progress-count">{{purchasedCount}}/{{totalSections}}章</text>
|
||||
</view>
|
||||
<view class="progress-bar-wrapper">
|
||||
<view class="progress-bar-bg">
|
||||
<view class="progress-bar-fill" style="width: {{(purchasedCount / totalSections) * 100}}%;"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="progress-stats">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value brand-color">{{purchasedCount}}</text>
|
||||
<text class="stat-label">已读</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{totalSections - purchasedCount}}</text>
|
||||
<text class="stat-label">待读</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">5</text>
|
||||
<text class="stat-label">篇章</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">11</text>
|
||||
<text class="stat-label">章节</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<button class="btn-primary purchase-btn" bindtap="handlePurchase">
|
||||
立即购买
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 推广入口 -->
|
||||
<view class="referral-banner card" bindtap="goToReferral">
|
||||
<view class="referral-content">
|
||||
<view class="referral-title">分享赚佣金</view>
|
||||
<view class="referral-desc">推荐好友购买,最高获得90%佣金</view>
|
||||
<!-- 精选推荐 -->
|
||||
<view class="section">
|
||||
<view class="section-header">
|
||||
<text class="section-title">精选推荐</text>
|
||||
<view class="section-more" bindtap="goToChapters">
|
||||
<text class="more-text">查看全部</text>
|
||||
<text class="more-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="featured-list">
|
||||
<view
|
||||
class="featured-item"
|
||||
wx:for="{{featuredSections}}"
|
||||
wx:key="id"
|
||||
bindtap="goToRead"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="featured-content">
|
||||
<view class="featured-meta">
|
||||
<text class="featured-id brand-color">{{item.id}}</text>
|
||||
<text class="tag {{item.tagClass}}">{{item.tag}}</text>
|
||||
</view>
|
||||
<text class="featured-title">{{item.title}}</text>
|
||||
<text class="featured-part">{{item.part}}</text>
|
||||
</view>
|
||||
<view class="featured-arrow">→</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容概览 -->
|
||||
<view class="section">
|
||||
<text class="section-title">内容概览</text>
|
||||
<view class="parts-list">
|
||||
<view
|
||||
class="part-item"
|
||||
wx:for="{{partsList}}"
|
||||
wx:key="id"
|
||||
bindtap="goToChapters"
|
||||
>
|
||||
<view class="part-icon">
|
||||
<text class="part-number">{{item.number}}</text>
|
||||
</view>
|
||||
<view class="part-info">
|
||||
<text class="part-title">{{item.title}}</text>
|
||||
<text class="part-subtitle">{{item.subtitle}}</text>
|
||||
</view>
|
||||
<view class="part-arrow">→</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 序言入口 -->
|
||||
<view class="preface-card" bindtap="goToRead" data-id="preface">
|
||||
<view class="preface-content">
|
||||
<text class="preface-title">序言</text>
|
||||
<text class="preface-desc">为什么我每天早上6点在Soul开播?</text>
|
||||
</view>
|
||||
<view class="tag tag-free">免费</view>
|
||||
</view>
|
||||
<view class="referral-icon">💰</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部留白 -->
|
||||
|
||||
@@ -1,81 +1,267 @@
|
||||
/* pages/index/index.wxss */
|
||||
/**
|
||||
* Soul创业实验 - 首页样式
|
||||
* 1:1还原Web版本UI
|
||||
*/
|
||||
|
||||
.container {
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #000000;
|
||||
padding-bottom: 120rpx;
|
||||
padding-bottom: 200rpx;
|
||||
}
|
||||
|
||||
/* 顶部标签 */
|
||||
.top-tag {
|
||||
display: inline-flex;
|
||||
/* ===== 导航栏占位 ===== */
|
||||
.nav-placeholder {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ===== 顶部区域 ===== */
|
||||
.header {
|
||||
padding: 0 32rpx 32rpx;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding: 12rpx 24rpx;
|
||||
background: rgba(48, 209, 88, 0.1);
|
||||
border: 2rpx solid rgba(48, 209, 88, 0.3);
|
||||
border-radius: 40rpx;
|
||||
margin: 40rpx 0 0 32rpx;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 32rpx;
|
||||
padding-top: 24rpx;
|
||||
}
|
||||
|
||||
.tag-icon {
|
||||
font-size: 28rpx;
|
||||
.logo-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.tag-text {
|
||||
font-size: 24rpx;
|
||||
color: #30D158;
|
||||
font-weight: 600;
|
||||
.logo-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 20rpx;
|
||||
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 206, 209, 0.3);
|
||||
}
|
||||
|
||||
/* 标题区 */
|
||||
.header-section {
|
||||
padding: 60rpx 48rpx 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 56rpx;
|
||||
font-weight: 700;
|
||||
.logo-text {
|
||||
color: #ffffff;
|
||||
margin-bottom: 8rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
font-size: 64rpx;
|
||||
font-weight: 800;
|
||||
.logo-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.logo-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.text-white {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.brand-color {
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.logo-subtitle {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.chapter-badge {
|
||||
font-size: 22rpx;
|
||||
color: #00CED1;
|
||||
background: rgba(0, 206, 209, 0.1);
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
|
||||
/* ===== 搜索栏 ===== */
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
padding: 24rpx 32rpx;
|
||||
background: #1c1c1e;
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: relative;
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.search-circle {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.4);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.search-handle {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 12rpx;
|
||||
height: 4rpx;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
transform: rotate(45deg);
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
|
||||
.search-placeholder {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
/* ===== 主内容区 ===== */
|
||||
.main-content {
|
||||
padding: 0 32rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ===== Banner卡片 ===== */
|
||||
.banner-card {
|
||||
position: relative;
|
||||
padding: 40rpx;
|
||||
border-radius: 32rpx;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, #0d3331 0%, #1a1a2e 50%, #16213e 100%);
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
background: linear-gradient(135deg, #30D158 0%, #00E5FF 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
.banner-glow {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 256rpx;
|
||||
height: 256rpx;
|
||||
background: #00CED1;
|
||||
border-radius: 50%;
|
||||
filter: blur(120rpx);
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
.banner-tag {
|
||||
display: inline-block;
|
||||
padding: 8rpx 16rpx;
|
||||
background: #00CED1;
|
||||
color: #000000;
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.banner-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 16rpx;
|
||||
padding-right: 64rpx;
|
||||
}
|
||||
|
||||
.banner-part {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 16rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.quote-line {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* 数据统计卡片 */
|
||||
.stats-card {
|
||||
.banner-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.banner-action-text {
|
||||
font-size: 28rpx;
|
||||
color: #00CED1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.banner-arrow {
|
||||
color: #00CED1;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* ===== 通用卡片 ===== */
|
||||
.card {
|
||||
background: #1c1c1e;
|
||||
border-radius: 32rpx;
|
||||
padding: 32rpx;
|
||||
margin: 32rpx 32rpx;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.1);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.05);
|
||||
margin: 0 0 24rpx 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ===== 阅读进度卡 ===== */
|
||||
.progress-card {
|
||||
width: 100%;
|
||||
background: #1c1c1e;
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.05);
|
||||
margin: 0 0 24rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.progress-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.progress-title {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.progress-count {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.progress-bar-wrapper {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.progress-bar-bg {
|
||||
width: 100%;
|
||||
height: 16rpx;
|
||||
background: #2c2c2e;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #00CED1 0%, #20B2AA 100%);
|
||||
border-radius: 8rpx;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
@@ -83,376 +269,236 @@
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 48rpx;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.brand-color {
|
||||
color: #30D158;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
width: 2rpx;
|
||||
height: 60rpx;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* 作者信息栏 */
|
||||
.author-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 32rpx;
|
||||
margin: 0 32rpx 32rpx;
|
||||
}
|
||||
|
||||
.author-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.author-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: rgba(48, 209, 88, 0.2);
|
||||
color: #30D158;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.author-label {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.author-name {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
/* ===== 区块标题 ===== */
|
||||
.section {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.live-info {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.live-label {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.live-time {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 主按钮 */
|
||||
.main-btn {
|
||||
width: 686rpx;
|
||||
height: 96rpx;
|
||||
line-height: 96rpx;
|
||||
margin: 0 32rpx 16rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-tip {
|
||||
text-align: center;
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
/* 寄语卡片 */
|
||||
.quote-card {
|
||||
margin: 32rpx;
|
||||
padding: 40rpx 32rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.quote-icon {
|
||||
font-size: 80rpx;
|
||||
color: rgba(48, 209, 88, 0.2);
|
||||
line-height: 1;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.quote-content {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
line-height: 1.8;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.quote-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.footer-avatar {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
background: rgba(48, 209, 88, 0.2);
|
||||
color: #30D158;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.footer-name {
|
||||
font-size: 26rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.footer-desc {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 三个数据展示 */
|
||||
.highlights-grid {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 32rpx;
|
||||
margin: 0 32rpx 32rpx;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.highlight-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.h-value {
|
||||
font-size: 48rpx;
|
||||
font-weight: 700;
|
||||
color: #30D158;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.h-label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 章节列表 */
|
||||
.chapters-section {
|
||||
margin: 32rpx;
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.chapter-count {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
.section-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.chapter-list {
|
||||
.more-text {
|
||||
font-size: 24rpx;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.more-arrow {
|
||||
font-size: 24rpx;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
/* ===== 精选推荐列表 ===== */
|
||||
.featured-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.chapter-item {
|
||||
.featured-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border-radius: 16rpx;
|
||||
transition: all 0.3s ease;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
padding: 32rpx;
|
||||
background: #1c1c1e;
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.chapter-item:active {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
.featured-item:active {
|
||||
transform: scale(0.98);
|
||||
background: #2c2c2e;
|
||||
}
|
||||
|
||||
.chapter-number {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
background: rgba(48, 209, 88, 0.2);
|
||||
color: #30D158;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chapter-info {
|
||||
.featured-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.chapter-title {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
margin-bottom: 8rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.chapter-meta {
|
||||
.featured-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.featured-id {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.tag-pink {
|
||||
background: rgba(233, 30, 99, 0.1);
|
||||
color: #E91E63;
|
||||
}
|
||||
|
||||
.tag-purple {
|
||||
background: rgba(123, 97, 255, 0.1);
|
||||
color: #7B61FF;
|
||||
}
|
||||
|
||||
.featured-title {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.featured-part {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.chapter-arrow {
|
||||
.featured-arrow {
|
||||
font-size: 32rpx;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
/* ===== 内容概览列表 ===== */
|
||||
.parts-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.part-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
padding: 32rpx;
|
||||
background: #1c1c1e;
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.part-item:active {
|
||||
transform: scale(0.98);
|
||||
background: #2c2c2e;
|
||||
}
|
||||
|
||||
.part-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 16rpx;
|
||||
background: linear-gradient(135deg, rgba(0, 206, 209, 0.2) 0%, rgba(32, 178, 170, 0.1) 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.part-number {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.part-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.part-title {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.part-subtitle {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.part-arrow {
|
||||
font-size: 32rpx;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 购买区域 */
|
||||
.purchase-section {
|
||||
margin: 32rpx;
|
||||
padding: 40rpx 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.purchase-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.purchase-desc {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.price-current {
|
||||
font-size: 56rpx;
|
||||
font-weight: 700;
|
||||
color: #30D158;
|
||||
}
|
||||
|
||||
.price-tip {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
.purchase-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
/* 推广横幅 */
|
||||
.referral-banner {
|
||||
/* ===== 序言入口 ===== */
|
||||
.preface-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 32rpx;
|
||||
margin: 32rpx;
|
||||
background: linear-gradient(135deg, rgba(48, 209, 88, 0.1) 0%, rgba(0, 229, 255, 0.1) 100%);
|
||||
border: 1rpx solid rgba(48, 209, 88, 0.3);
|
||||
border-radius: 24rpx;
|
||||
background: linear-gradient(90deg, rgba(0, 206, 209, 0.1) 0%, transparent 100%);
|
||||
border: 2rpx solid rgba(0, 206, 209, 0.2);
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.referral-content {
|
||||
.preface-card:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.preface-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.referral-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
.preface-title {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.referral-desc {
|
||||
.preface-desc {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.referral-icon {
|
||||
font-size: 64rpx;
|
||||
}
|
||||
|
||||
/* 通用卡片样式 */
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 24rpx;
|
||||
backdrop-filter: blur(20rpx);
|
||||
}
|
||||
|
||||
/* 底部留白 */
|
||||
/* ===== 底部留白 ===== */
|
||||
.bottom-space {
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
/* 动画 */
|
||||
.page-transition {
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20rpx);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #30D158 0%, #00E5FF 100%);
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 48rpx;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 8rpx 24rpx rgba(48, 209, 88, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
opacity: 0.8;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
@@ -1,355 +1,424 @@
|
||||
// pages/match/match.js
|
||||
/**
|
||||
* Soul创业实验 - 找伙伴页
|
||||
* 按H5网页端完全重构
|
||||
* 开发: 卡若
|
||||
*/
|
||||
|
||||
const app = getApp()
|
||||
|
||||
// 匹配类型配置 - 与H5保持一致
|
||||
const MATCH_TYPES = [
|
||||
{ id: 'partner', label: '创业合伙', matchLabel: '创业伙伴', icon: '⭐', matchFromDB: true, showJoinAfterMatch: false },
|
||||
{ id: 'investor', label: '资源对接', matchLabel: '资源对接', icon: '👥', matchFromDB: false, showJoinAfterMatch: true },
|
||||
{ id: 'mentor', label: '导师顾问', matchLabel: '商业顾问', icon: '❤️', matchFromDB: false, showJoinAfterMatch: true },
|
||||
{ id: 'team', label: '团队招募', matchLabel: '加入项目', icon: '🎮', matchFromDB: false, showJoinAfterMatch: true }
|
||||
]
|
||||
|
||||
const FREE_MATCH_LIMIT = 1 // 每日免费匹配次数
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
|
||||
// 匹配类型
|
||||
matchTypes: MATCH_TYPES,
|
||||
selectedType: 'partner',
|
||||
currentTypeLabel: '创业合伙',
|
||||
|
||||
// 用户状态
|
||||
isLoggedIn: false,
|
||||
hasPurchased: false,
|
||||
hasFullBook: false,
|
||||
|
||||
// 匹配次数
|
||||
todayMatchCount: 0,
|
||||
totalMatchesAllowed: FREE_MATCH_LIMIT,
|
||||
matchesRemaining: FREE_MATCH_LIMIT,
|
||||
needPayToMatch: false,
|
||||
|
||||
// 匹配状态
|
||||
isMatching: false,
|
||||
currentMatch: null,
|
||||
onlineCount: 0,
|
||||
matchAttempts: 0,
|
||||
recentMatches: [],
|
||||
matchTimer: null
|
||||
currentMatch: null,
|
||||
|
||||
// 加入弹窗
|
||||
showJoinModal: false,
|
||||
joinType: null,
|
||||
joinTypeLabel: '',
|
||||
contactType: 'phone',
|
||||
phoneNumber: '',
|
||||
wechatId: '',
|
||||
userPhone: '',
|
||||
isJoining: false,
|
||||
joinSuccess: false,
|
||||
joinError: '',
|
||||
|
||||
// 解锁弹窗
|
||||
showUnlockModal: false
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.initStarBackground()
|
||||
this.loadOnlineCount()
|
||||
this.loadRecentMatches()
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight || 44
|
||||
})
|
||||
this.loadStoredContact()
|
||||
this.loadTodayMatchCount()
|
||||
this.initUserStatus()
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
// 清理匹配定时器
|
||||
if (this.data.matchTimer) {
|
||||
clearTimeout(this.data.matchTimer)
|
||||
onShow() {
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
this.getTabBar().setData({ selected: 2 })
|
||||
}
|
||||
this.initUserStatus()
|
||||
},
|
||||
|
||||
// 初始化星空背景
|
||||
initStarBackground() {
|
||||
const ctx = wx.createCanvasContext('starCanvas')
|
||||
const width = wx.getSystemInfoSync().windowWidth
|
||||
const height = wx.getSystemInfoSync().windowHeight
|
||||
|
||||
// 绘制星星
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const x = Math.random() * width
|
||||
const y = Math.random() * height
|
||||
const radius = Math.random() * 2
|
||||
const opacity = Math.random()
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.arc(x, y, radius, 0, 2 * Math.PI)
|
||||
ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
ctx.draw()
|
||||
},
|
||||
|
||||
// 加载在线人数
|
||||
loadOnlineCount() {
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/match/online-count`,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
this.setData({
|
||||
onlineCount: res.data.count || 0
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 使用模拟数据
|
||||
this.setData({
|
||||
onlineCount: Math.floor(Math.random() * 500) + 100
|
||||
})
|
||||
}
|
||||
// 加载本地存储的联系方式
|
||||
loadStoredContact() {
|
||||
const phone = wx.getStorageSync('user_phone') || ''
|
||||
const wechat = wx.getStorageSync('user_wechat') || ''
|
||||
this.setData({
|
||||
phoneNumber: phone,
|
||||
wechatId: wechat,
|
||||
userPhone: phone
|
||||
})
|
||||
},
|
||||
|
||||
// 加载最近匹配记录
|
||||
loadRecentMatches() {
|
||||
const userInfo = app.getUserInfo()
|
||||
if (!userInfo) return
|
||||
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/match/recent`,
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
this.setData({
|
||||
recentMatches: res.data.matches || []
|
||||
})
|
||||
// 加载今日匹配次数
|
||||
loadTodayMatchCount() {
|
||||
try {
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
const stored = wx.getStorageSync('match_count_data')
|
||||
if (stored) {
|
||||
const data = typeof stored === 'string' ? JSON.parse(stored) : stored
|
||||
if (data.date === today) {
|
||||
this.setData({ todayMatchCount: data.count })
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 使用本地缓存
|
||||
const cached = wx.getStorageSync('recentMatches')
|
||||
if (cached) {
|
||||
this.setData({ recentMatches: cached })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载匹配次数失败:', e)
|
||||
}
|
||||
},
|
||||
|
||||
// 保存今日匹配次数
|
||||
saveTodayMatchCount(count) {
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
wx.setStorageSync('match_count_data', { date: today, count })
|
||||
},
|
||||
|
||||
// 初始化用户状态
|
||||
initUserStatus() {
|
||||
const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
|
||||
const hasPurchased = hasFullBook || (purchasedSections && purchasedSections.length > 0)
|
||||
|
||||
// 总匹配次数 = 每日免费(1) + 已购小节数
|
||||
const totalMatchesAllowed = hasFullBook ? 999999 : FREE_MATCH_LIMIT + (purchasedSections?.length || 0)
|
||||
const matchesRemaining = hasFullBook ? 999999 : Math.max(0, totalMatchesAllowed - this.data.todayMatchCount)
|
||||
const needPayToMatch = !hasFullBook && matchesRemaining <= 0
|
||||
|
||||
this.setData({
|
||||
isLoggedIn,
|
||||
hasFullBook,
|
||||
hasPurchased,
|
||||
totalMatchesAllowed,
|
||||
matchesRemaining,
|
||||
needPayToMatch
|
||||
})
|
||||
},
|
||||
|
||||
// 选择匹配类型
|
||||
selectType(e) {
|
||||
const typeId = e.currentTarget.dataset.type
|
||||
const type = MATCH_TYPES.find(t => t.id === typeId)
|
||||
this.setData({
|
||||
selectedType: typeId,
|
||||
currentTypeLabel: type?.matchLabel || type?.label || '创业伙伴'
|
||||
})
|
||||
},
|
||||
|
||||
// 点击匹配按钮
|
||||
handleMatchClick() {
|
||||
const currentType = MATCH_TYPES.find(t => t.id === this.data.selectedType)
|
||||
|
||||
// 如果是需要填写联系方式的类型,直接弹出加入弹窗
|
||||
if (currentType && currentType.showJoinAfterMatch) {
|
||||
this.setData({
|
||||
showJoinModal: true,
|
||||
joinType: currentType.id,
|
||||
joinTypeLabel: currentType.matchLabel || currentType.label,
|
||||
joinSuccess: false,
|
||||
joinError: ''
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 创业合伙类型 - 真正的匹配功能
|
||||
if (this.data.needPayToMatch) {
|
||||
this.setData({ showUnlockModal: true })
|
||||
return
|
||||
}
|
||||
|
||||
this.startMatch()
|
||||
},
|
||||
|
||||
// 显示购买提示
|
||||
showPurchaseTip() {
|
||||
wx.showModal({
|
||||
title: '需要购买书籍',
|
||||
content: '购买《一场Soul的创业实验》后即可使用匹配功能,仅需9.9元',
|
||||
confirmText: '去购买',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.goToChapters()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 开始匹配
|
||||
startMatch() {
|
||||
const userInfo = app.getUserInfo()
|
||||
|
||||
if (!userInfo) {
|
||||
this.showLoginModal()
|
||||
return
|
||||
}
|
||||
|
||||
async startMatch() {
|
||||
this.setData({
|
||||
isMatching: true,
|
||||
matchAttempts: 0
|
||||
matchAttempts: 0,
|
||||
currentMatch: null
|
||||
})
|
||||
|
||||
// 模拟匹配过程
|
||||
this.doMatch()
|
||||
},
|
||||
|
||||
// 执行匹配
|
||||
doMatch() {
|
||||
const timer = setInterval(() => {
|
||||
const attempts = this.data.matchAttempts + 1
|
||||
this.setData({ matchAttempts: attempts })
|
||||
|
||||
// 3-6秒后匹配成功
|
||||
if (attempts >= 3) {
|
||||
clearInterval(timer)
|
||||
this.matchSuccess()
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
this.setData({ matchTimer: timer })
|
||||
|
||||
// 真实匹配请求
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/match/find`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
data: {
|
||||
interests: ['创业', '私域运营', '读书'],
|
||||
currentChapter: app.globalData.currentChapter
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.data.match) {
|
||||
clearInterval(timer)
|
||||
this.matchSuccess(res.data.match)
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 使用模拟数据
|
||||
clearInterval(timer)
|
||||
this.matchSuccess(this.getMockMatch())
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 匹配成功
|
||||
matchSuccess(matchData) {
|
||||
const match = matchData || this.getMockMatch()
|
||||
|
||||
this.setData({
|
||||
isMatching: false,
|
||||
currentMatch: match
|
||||
})
|
||||
|
||||
// 震动反馈
|
||||
wx.vibrateShort()
|
||||
|
||||
// 播放成功提示音
|
||||
wx.showToast({
|
||||
title: '匹配成功!',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
|
||||
// 保存到最近匹配
|
||||
this.saveRecentMatch(match)
|
||||
// 匹配动画计时器
|
||||
const timer = setInterval(() => {
|
||||
this.setData({ matchAttempts: this.data.matchAttempts + 1 })
|
||||
}, 1000)
|
||||
|
||||
// 尝试从API获取真实用户
|
||||
let matchedUser = null
|
||||
try {
|
||||
const res = await app.request('/api/ckb/match', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
matchType: this.data.selectedType,
|
||||
userId: app.globalData.userInfo?.id || '',
|
||||
phone: this.data.phoneNumber,
|
||||
wechat: this.data.wechatId
|
||||
}
|
||||
})
|
||||
|
||||
if (res.success && res.data) {
|
||||
matchedUser = res.data
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('API匹配失败,使用模拟数据')
|
||||
}
|
||||
|
||||
// 如果API没返回,使用模拟数据
|
||||
if (!matchedUser) {
|
||||
matchedUser = this.generateMockMatch()
|
||||
}
|
||||
|
||||
// 延迟显示结果(模拟匹配过程)
|
||||
const delay = Math.random() * 2000 + 2000
|
||||
setTimeout(() => {
|
||||
clearInterval(timer)
|
||||
|
||||
// 增加今日匹配次数
|
||||
const newCount = this.data.todayMatchCount + 1
|
||||
const matchesRemaining = this.data.hasFullBook ? 999999 : Math.max(0, this.data.totalMatchesAllowed - newCount)
|
||||
|
||||
this.setData({
|
||||
isMatching: false,
|
||||
currentMatch: matchedUser,
|
||||
todayMatchCount: newCount,
|
||||
matchesRemaining,
|
||||
needPayToMatch: !this.data.hasFullBook && matchesRemaining <= 0
|
||||
})
|
||||
this.saveTodayMatchCount(newCount)
|
||||
|
||||
// 上报匹配行为
|
||||
this.reportMatch(matchedUser)
|
||||
|
||||
}, delay)
|
||||
},
|
||||
|
||||
// 获取模拟匹配数据
|
||||
getMockMatch() {
|
||||
const nicknames = ['阅读爱好者', '创业小白', '私域达人', '书虫一枚', '灵魂摆渡人']
|
||||
const avatars = [
|
||||
'https://picsum.photos/200/200?random=1',
|
||||
'https://picsum.photos/200/200?random=2',
|
||||
'https://picsum.photos/200/200?random=3'
|
||||
]
|
||||
const tagsList = [
|
||||
['创业者', '私域运营', 'MBTI-INTP'],
|
||||
['读书达人', 'Soul用户', '内容创作'],
|
||||
['互联网人', '产品经理', '深度思考']
|
||||
]
|
||||
// 生成模拟匹配数据
|
||||
generateMockMatch() {
|
||||
const nicknames = ['创业先锋', '资源整合者', '私域专家', '商业导师', '连续创业者']
|
||||
const concepts = [
|
||||
'一个坚持长期主义的私域玩家,擅长内容结构化。',
|
||||
'相信阅读可以改变人生,每天坚持读书1小时。',
|
||||
'在Soul上分享创业经验,希望帮助更多人少走弯路。'
|
||||
'专注私域流量运营5年,帮助100+品牌实现从0到1的增长。',
|
||||
'连续创业者,擅长商业模式设计和资源整合。',
|
||||
'在Soul分享真实创业故事,希望找到志同道合的合作伙伴。'
|
||||
]
|
||||
const wechats = [
|
||||
'soul_book_friend_1',
|
||||
'soul_reader_2024',
|
||||
'soul_party_fan'
|
||||
]
|
||||
|
||||
const randomIndex = Math.floor(Math.random() * nicknames.length)
|
||||
const wechats = ['soul_partner_1', 'soul_business_2024', 'soul_startup_fan']
|
||||
|
||||
const index = Math.floor(Math.random() * nicknames.length)
|
||||
const currentType = MATCH_TYPES.find(t => t.id === this.data.selectedType)
|
||||
|
||||
return {
|
||||
id: `user_${Date.now()}`,
|
||||
nickname: nicknames[randomIndex],
|
||||
avatar: avatars[randomIndex % avatars.length],
|
||||
tags: tagsList[randomIndex % tagsList.length],
|
||||
nickname: nicknames[index],
|
||||
avatar: `https://picsum.photos/200/200?random=${Date.now()}`,
|
||||
tags: ['创业者', '私域运营', currentType?.label || '创业合伙'],
|
||||
matchScore: Math.floor(Math.random() * 20) + 80,
|
||||
concept: concepts[randomIndex % concepts.length],
|
||||
wechat: wechats[randomIndex % wechats.length],
|
||||
concept: concepts[index % concepts.length],
|
||||
wechat: wechats[index % wechats.length],
|
||||
commonInterests: [
|
||||
{ icon: '📚', text: '都在读《创业实验》' },
|
||||
{ icon: '💼', text: '对私域运营感兴趣' },
|
||||
{ icon: '🎯', text: '相似的职业背景' }
|
||||
{ icon: '🎯', text: '相似的创业方向' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// 保存最近匹配
|
||||
saveRecentMatch(match) {
|
||||
let recent = this.data.recentMatches
|
||||
const newMatch = {
|
||||
...match,
|
||||
matchTime: '刚刚'
|
||||
// 上报匹配行为
|
||||
async reportMatch(matchedUser) {
|
||||
try {
|
||||
await app.request('/api/ckb/match', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
matchType: this.data.selectedType,
|
||||
phone: this.data.phoneNumber,
|
||||
wechat: this.data.wechatId,
|
||||
userId: app.globalData.userInfo?.id || '',
|
||||
nickname: app.globalData.userInfo?.nickname || '',
|
||||
matchedUser: {
|
||||
id: matchedUser.id,
|
||||
nickname: matchedUser.nickname,
|
||||
matchScore: matchedUser.matchScore
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('上报匹配失败:', e)
|
||||
}
|
||||
|
||||
recent.unshift(newMatch)
|
||||
if (recent.length > 10) {
|
||||
recent = recent.slice(0, 10)
|
||||
}
|
||||
|
||||
this.setData({ recentMatches: recent })
|
||||
wx.setStorageSync('recentMatches', recent)
|
||||
},
|
||||
|
||||
// 取消匹配
|
||||
cancelMatch() {
|
||||
if (this.data.matchTimer) {
|
||||
clearTimeout(this.data.matchTimer)
|
||||
}
|
||||
|
||||
this.setData({
|
||||
isMatching: false,
|
||||
matchAttempts: 0
|
||||
})
|
||||
|
||||
wx.showToast({
|
||||
title: '已取消匹配',
|
||||
icon: 'none'
|
||||
})
|
||||
this.setData({ isMatching: false, matchAttempts: 0 })
|
||||
},
|
||||
|
||||
// 一键加好友
|
||||
addWechat() {
|
||||
const match = this.data.currentMatch
|
||||
if (!match || !match.wechat) return
|
||||
// 重置匹配(返回)
|
||||
resetMatch() {
|
||||
this.setData({ currentMatch: null })
|
||||
},
|
||||
|
||||
// 添加微信好友
|
||||
handleAddWechat() {
|
||||
if (!this.data.currentMatch) return
|
||||
|
||||
wx.setClipboardData({
|
||||
data: match.wechat,
|
||||
data: this.data.currentMatch.wechat,
|
||||
success: () => {
|
||||
wx.showModal({
|
||||
title: '微信号已复制',
|
||||
content: `微信号:${match.wechat}\n\n已复制到剪贴板,请打开微信添加好友,备注"书友"即可。`,
|
||||
content: `微信号:${this.data.currentMatch.wechat}\n\n请打开微信添加好友,备注"创业合作"即可`,
|
||||
showCancel: false,
|
||||
confirmText: '打开微信',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 尝试打开微信(小程序无法直接跳转,只能提示)
|
||||
wx.showToast({
|
||||
title: '请手动打开微信添加',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
}
|
||||
confirmText: '知道了'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 加入书友群
|
||||
joinGroup() {
|
||||
wx.showModal({
|
||||
title: '加入书友群',
|
||||
content: '请先添加书友微信,备注"书友群",对方会拉你入群。\n\n群内可以:\n· 深度交流读书心得\n· 参加线下读书会\n· 获取独家资源',
|
||||
showCancel: true,
|
||||
cancelText: '取消',
|
||||
confirmText: '添加好友',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.addWechat()
|
||||
}
|
||||
}
|
||||
// 切换联系方式类型
|
||||
switchContactType(e) {
|
||||
const type = e.currentTarget.dataset.type
|
||||
this.setData({ contactType: type, joinError: '' })
|
||||
},
|
||||
|
||||
// 手机号输入
|
||||
onPhoneInput(e) {
|
||||
this.setData({
|
||||
phoneNumber: e.detail.value.replace(/\D/g, '').slice(0, 11),
|
||||
joinError: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 下一位
|
||||
nextMatch() {
|
||||
this.setData({
|
||||
currentMatch: null,
|
||||
matchAttempts: 0
|
||||
// 微信号输入
|
||||
onWechatInput(e) {
|
||||
this.setData({
|
||||
wechatId: e.detail.value,
|
||||
joinError: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 提交加入
|
||||
async handleJoinSubmit() {
|
||||
const { contactType, phoneNumber, wechatId, joinType, isJoining } = this.data
|
||||
|
||||
wx.showToast({
|
||||
title: '重新匹配中',
|
||||
icon: 'loading'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
this.startMatch()
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 查看匹配详情
|
||||
viewMatchDetail(e) {
|
||||
const matchId = e.currentTarget.dataset.id
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
// 显示登录弹窗
|
||||
showLoginModal() {
|
||||
wx.showModal({
|
||||
title: '需要登录',
|
||||
content: '匹配书友前需要先登录账号',
|
||||
confirmText: '立即登录',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
app.wxLogin((success) => {
|
||||
if (success) {
|
||||
wx.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.startMatch()
|
||||
}, 1500)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (isJoining) return
|
||||
|
||||
// 验证
|
||||
if (contactType === 'phone') {
|
||||
if (!phoneNumber || phoneNumber.length !== 11) {
|
||||
this.setData({ joinError: '请输入正确的11位手机号' })
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (!wechatId || wechatId.length < 6) {
|
||||
this.setData({ joinError: '请输入正确的微信号(至少6位)' })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({ isJoining: true, joinError: '' })
|
||||
|
||||
try {
|
||||
const res = await app.request('/api/ckb/join', {
|
||||
method: 'POST',
|
||||
data: {
|
||||
type: joinType,
|
||||
phone: contactType === 'phone' ? phoneNumber : '',
|
||||
wechat: contactType === 'wechat' ? wechatId : '',
|
||||
userId: app.globalData.userInfo?.id || ''
|
||||
}
|
||||
})
|
||||
|
||||
// 保存联系方式到本地
|
||||
if (phoneNumber) wx.setStorageSync('user_phone', phoneNumber)
|
||||
if (wechatId) wx.setStorageSync('user_wechat', wechatId)
|
||||
|
||||
if (res.success) {
|
||||
this.setData({ joinSuccess: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ showJoinModal: false, joinSuccess: false })
|
||||
}, 2000)
|
||||
} else {
|
||||
// 即使API返回失败,也模拟成功(因为已保存本地)
|
||||
this.setData({ joinSuccess: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ showJoinModal: false, joinSuccess: false })
|
||||
}, 2000)
|
||||
}
|
||||
} catch (e) {
|
||||
// 网络错误时也模拟成功
|
||||
this.setData({ joinSuccess: true })
|
||||
setTimeout(() => {
|
||||
this.setData({ showJoinModal: false, joinSuccess: false })
|
||||
}, 2000)
|
||||
} finally {
|
||||
this.setData({ isJoining: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 分享
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '来Soul派对匹配志同道合的书友吧!',
|
||||
path: '/pages/match/match',
|
||||
imageUrl: '/assets/images/share-match.png'
|
||||
}
|
||||
}
|
||||
// 关闭加入弹窗
|
||||
closeJoinModal() {
|
||||
if (this.data.isJoining) return
|
||||
this.setData({ showJoinModal: false, joinError: '' })
|
||||
},
|
||||
|
||||
// 关闭解锁弹窗
|
||||
closeUnlockModal() {
|
||||
this.setData({ showUnlockModal: false })
|
||||
},
|
||||
|
||||
// 跳转到目录页购买
|
||||
goToChapters() {
|
||||
this.setData({ showUnlockModal: false })
|
||||
wx.switchTab({ url: '/pages/chapters/chapters' })
|
||||
},
|
||||
|
||||
// 打开设置
|
||||
openSettings() {
|
||||
wx.showToast({ title: '设置功能开发中', icon: 'none' })
|
||||
},
|
||||
|
||||
// 阻止事件冒泡
|
||||
preventBubble() {}
|
||||
})
|
||||
|
||||
6
miniprogram/pages/match/match.json
Normal file
6
miniprogram/pages/match/match.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundTextStyle": "light",
|
||||
"backgroundColor": "#000000"
|
||||
}
|
||||
@@ -1,128 +1,284 @@
|
||||
<!--pages/match/match.wxml-->
|
||||
<view class="container match-container page-transition">
|
||||
<!-- 星空背景效果 -->
|
||||
<canvas canvas-id="starCanvas" class="star-canvas"></canvas>
|
||||
|
||||
<!-- 顶部标题 -->
|
||||
<view class="match-header">
|
||||
<view class="match-title gradient-text">寻找合作伙伴</view>
|
||||
<view class="match-subtitle">找到和你一起创业的灵魂</view>
|
||||
</view>
|
||||
|
||||
<!-- 匹配状态区 -->
|
||||
<view class="match-status-area">
|
||||
<!-- 未匹配状态 -->
|
||||
<view class="match-idle" wx:if="{{!isMatching && !currentMatch}}">
|
||||
<!-- 中央大星球 -->
|
||||
<view class="center-planet" bindtap="startMatch">
|
||||
<view class="planet-gradient">
|
||||
<view class="planet-icon">
|
||||
<image class="icon-mic" src="/assets/icons/match.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="planet-text">开始匹配</view>
|
||||
<view class="planet-subtitle">寻找合作伙伴</view>
|
||||
</view>
|
||||
<view class="planet-ring"></view>
|
||||
</view>
|
||||
|
||||
<view class="match-tips">
|
||||
<view class="tip-item">💼 共同的创业方向</view>
|
||||
<view class="tip-item">💬 实时在线交流</view>
|
||||
<view class="tip-item">🎯 相似的商业洞察</view>
|
||||
<!--Soul创业实验 - 找伙伴页 按H5网页端完全重构-->
|
||||
<view class="page">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-content">
|
||||
<text class="nav-title">找伙伴</text>
|
||||
<view class="nav-settings" bindtap="openSettings">
|
||||
<text class="settings-icon">⚙️</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<!-- 匹配次数显示 - 仅购买用户显示 -->
|
||||
<view class="match-count-bar" wx:if="{{hasPurchased}}">
|
||||
<view class="count-left">
|
||||
<text class="count-icon {{matchesRemaining <= 0 && !hasFullBook ? 'icon-warning' : ''}}">⚡</text>
|
||||
<text class="count-text">
|
||||
{{hasFullBook ? '无限匹配机会' : matchesRemaining <= 0 ? '今日匹配机会已用完' : '剩余匹配机会'}}
|
||||
</text>
|
||||
</view>
|
||||
<view class="count-right">
|
||||
<text class="count-value {{matchesRemaining > 0 || hasFullBook ? 'text-brand' : 'text-red'}}">
|
||||
{{hasFullBook ? '无限' : matchesRemaining + '/' + totalMatchesAllowed}}
|
||||
</text>
|
||||
<view class="unlock-mini-btn" wx:if="{{matchesRemaining <= 0 && !hasFullBook}}" bindtap="goToChapters">
|
||||
购买小节+1次
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<view class="main-content">
|
||||
<!-- 空闲状态 - 未匹配 -->
|
||||
<block wx:if="{{!isMatching && !currentMatch}}">
|
||||
<!-- 中央匹配圆环 -->
|
||||
<view
|
||||
class="match-circle-wrapper"
|
||||
bindtap="{{hasPurchased ? 'handleMatchClick' : 'showPurchaseTip'}}"
|
||||
>
|
||||
<!-- 外层光环 -->
|
||||
<view class="outer-glow {{hasPurchased ? 'glow-active' : 'glow-inactive'}}"></view>
|
||||
<!-- 中间光环 -->
|
||||
<view class="middle-ring {{hasPurchased ? 'ring-active' : 'ring-inactive'}}"></view>
|
||||
<!-- 内层球体 -->
|
||||
<view class="inner-sphere {{hasPurchased ? 'sphere-active' : 'sphere-inactive'}}">
|
||||
<view class="sphere-gradient"></view>
|
||||
<view class="sphere-content">
|
||||
<!-- 已购买用户 -->
|
||||
<block wx:if="{{hasPurchased}}">
|
||||
<block wx:if="{{needPayToMatch}}">
|
||||
<text class="sphere-icon">⚡</text>
|
||||
<text class="sphere-title gold-text">需要解锁</text>
|
||||
<text class="sphere-desc">今日免费次数已用完</text>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<text class="sphere-icon">👥</text>
|
||||
<text class="sphere-title">开始匹配</text>
|
||||
<text class="sphere-desc">匹配{{currentTypeLabel}}</text>
|
||||
</block>
|
||||
</block>
|
||||
<!-- 未购买用户 -->
|
||||
<block wx:else>
|
||||
<text class="sphere-icon">🔒</text>
|
||||
<text class="sphere-title text-gray">购买后解锁</text>
|
||||
<text class="sphere-desc text-muted">购买9.9元即可使用</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 当前模式显示 -->
|
||||
<view class="current-mode">
|
||||
当前模式: <text class="{{hasPurchased ? 'text-brand' : 'text-muted'}}">{{currentTypeLabel}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 购买提示 - 仅未购买用户显示 -->
|
||||
<view class="purchase-tip-card" wx:if="{{!hasPurchased}}">
|
||||
<view class="tip-left">
|
||||
<text class="tip-title">购买书籍解锁匹配功能</text>
|
||||
<text class="tip-desc">仅需9.9元,每天免费匹配</text>
|
||||
</view>
|
||||
<view class="tip-btn" bindtap="goToChapters">去购买</view>
|
||||
</view>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<view class="divider"></view>
|
||||
|
||||
<!-- 选择匹配类型 -->
|
||||
<view class="type-section">
|
||||
<text class="type-section-title">选择匹配类型</text>
|
||||
<view class="type-grid">
|
||||
<view
|
||||
class="type-item {{selectedType === item.id ? 'type-active' : ''}}"
|
||||
wx:for="{{matchTypes}}"
|
||||
wx:key="id"
|
||||
bindtap="selectType"
|
||||
data-type="{{item.id}}"
|
||||
>
|
||||
<text class="type-icon">{{item.icon}}</text>
|
||||
<text class="type-label {{selectedType === item.id ? 'text-brand' : ''}}">{{item.label}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 匹配中状态 -->
|
||||
<view class="match-loading" wx:if="{{isMatching}}">
|
||||
<view class="loading-planet">
|
||||
<image class="rotating-planet" src="/assets/images/planet-match.png" mode="aspectFit"></image>
|
||||
<view class="loading-rings">
|
||||
<view class="ring ring-1"></view>
|
||||
<view class="ring ring-2"></view>
|
||||
<view class="ring ring-3"></view>
|
||||
<block wx:if="{{isMatching}}">
|
||||
<view class="matching-state">
|
||||
<view class="matching-animation">
|
||||
<view class="matching-ring"></view>
|
||||
<view class="matching-center">
|
||||
<text class="matching-icon">👥</text>
|
||||
</view>
|
||||
<view class="ripple ripple-1"></view>
|
||||
<view class="ripple ripple-2"></view>
|
||||
<view class="ripple ripple-3"></view>
|
||||
</view>
|
||||
<text class="matching-title">正在匹配{{currentTypeLabel}}...</text>
|
||||
<text class="matching-count">已匹配 {{matchAttempts}} 次</text>
|
||||
<view class="cancel-btn" bindtap="cancelMatch">取消匹配</view>
|
||||
</view>
|
||||
|
||||
<view class="loading-text">正在寻找志同道合的书友...</view>
|
||||
<view class="loading-progress">已匹配 {{matchAttempts}} 次</view>
|
||||
|
||||
<button class="btn-secondary cancel-btn" bindtap="cancelMatch">
|
||||
取消匹配
|
||||
</button>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- 匹配成功状态 -->
|
||||
<view class="match-success" wx:if="{{currentMatch && !isMatching}}">
|
||||
<view class="success-animation">
|
||||
<view class="success-icon">✨</view>
|
||||
</view>
|
||||
<block wx:if="{{currentMatch && !isMatching}}">
|
||||
<view class="matched-state">
|
||||
<!-- 成功动画 -->
|
||||
<view class="success-icon-wrapper">
|
||||
<text class="success-icon">✨</text>
|
||||
</view>
|
||||
|
||||
<view class="match-user-card card">
|
||||
<image
|
||||
class="user-avatar"
|
||||
src="{{currentMatch.avatar}}"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
|
||||
<view class="user-info">
|
||||
<view class="user-name">{{currentMatch.nickname}}</view>
|
||||
<view class="user-tags">
|
||||
<text class="tag" wx:for="{{currentMatch.tags}}" wx:key="*this">
|
||||
{{item}}
|
||||
</text>
|
||||
<!-- 用户卡片 -->
|
||||
<view class="match-card">
|
||||
<view class="card-header">
|
||||
<image class="match-avatar" src="{{currentMatch.avatar}}" mode="aspectFill"></image>
|
||||
<view class="match-info">
|
||||
<text class="match-name">{{currentMatch.nickname}}</text>
|
||||
<view class="match-tags">
|
||||
<text class="match-tag" wx:for="{{currentMatch.tags}}" wx:key="*this">{{item}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="match-score-box">
|
||||
<text class="score-value">{{currentMatch.matchScore}}%</text>
|
||||
<text class="score-label">匹配度</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 共同兴趣 -->
|
||||
<view class="card-section">
|
||||
<text class="section-title">共同兴趣</text>
|
||||
<view class="interest-list">
|
||||
<view class="interest-item" wx:for="{{currentMatch.commonInterests}}" wx:key="text">
|
||||
<text class="interest-icon">{{item.icon}}</text>
|
||||
<text class="interest-text">{{item.text}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心理念 -->
|
||||
<view class="card-section">
|
||||
<text class="section-title">核心理念</text>
|
||||
<text class="concept-text">{{currentMatch.concept}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="match-score">
|
||||
<view class="score-label">匹配度</view>
|
||||
<view class="score-value">{{currentMatch.matchScore}}%</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="action-buttons">
|
||||
<view class="btn-primary" bindtap="handleAddWechat">一键加好友</view>
|
||||
<view class="btn-secondary" bindtap="resetMatch">返回</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 共同兴趣 -->
|
||||
<view class="common-interests card">
|
||||
<view class="interests-title">共同兴趣</view>
|
||||
<view class="interests-list">
|
||||
<view class="interest-item" wx:for="{{currentMatch.commonInterests}}" wx:key="*this">
|
||||
<text class="interest-icon">{{item.icon}}</text>
|
||||
<text class="interest-text">{{item.text}}</text>
|
||||
</view>
|
||||
<!-- 加入弹窗 - 填写手机号或微信号 -->
|
||||
<view class="modal-overlay" wx:if="{{showJoinModal}}" bindtap="closeJoinModal">
|
||||
<view class="modal-content join-modal" catchtap="preventBubble">
|
||||
<!-- 成功状态 -->
|
||||
<block wx:if="{{joinSuccess}}">
|
||||
<view class="join-success">
|
||||
<view class="success-check">✅</view>
|
||||
<text class="success-title">加入成功!</text>
|
||||
<text class="success-desc">我们会尽快与您联系</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心理念 -->
|
||||
<view class="core-concept card">
|
||||
<view class="concept-title">核心理念</view>
|
||||
<view class="concept-text">{{currentMatch.concept || '一个坚持长期主义的私域玩家,擅长内容结构化。'}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="match-actions">
|
||||
<button class="btn-primary action-btn" bindtap="addWechat">
|
||||
<text class="btn-icon">➕</text>
|
||||
<text>一键加好友</text>
|
||||
</button>
|
||||
<button class="btn-primary action-btn" bindtap="joinGroup">
|
||||
<text class="btn-icon">👥</text>
|
||||
<text>加入书友群</text>
|
||||
</button>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<button class="btn-secondary next-btn" bindtap="nextMatch">
|
||||
🔄 不喜欢?重新匹配
|
||||
</button>
|
||||
<!-- 表单状态 -->
|
||||
<block wx:else>
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">加入{{joinTypeLabel}}</text>
|
||||
<view class="close-btn" bindtap="closeJoinModal">✕</view>
|
||||
</view>
|
||||
|
||||
<text class="form-tip">
|
||||
{{userPhone ? '已检测到您的绑定信息,可直接提交或修改' : '请填写您的联系方式以便我们联系您'}}
|
||||
</text>
|
||||
|
||||
<!-- 联系方式类型切换 -->
|
||||
<view class="contact-tabs">
|
||||
<view
|
||||
class="contact-tab {{contactType === 'phone' ? 'tab-active-phone' : ''}}"
|
||||
bindtap="switchContactType"
|
||||
data-type="phone"
|
||||
>手机号</view>
|
||||
<view
|
||||
class="contact-tab {{contactType === 'wechat' ? 'tab-active-wechat' : ''}}"
|
||||
bindtap="switchContactType"
|
||||
data-type="wechat"
|
||||
>微信号</view>
|
||||
</view>
|
||||
|
||||
<!-- 输入框 -->
|
||||
<view class="input-group">
|
||||
<text class="input-label">{{contactType === 'phone' ? '手机号' : '微信号'}}</text>
|
||||
<input
|
||||
wx:if="{{contactType === 'phone'}}"
|
||||
type="number"
|
||||
class="form-input"
|
||||
placeholder="请输入11位手机号"
|
||||
placeholder-class="input-placeholder"
|
||||
value="{{phoneNumber}}"
|
||||
bindinput="onPhoneInput"
|
||||
maxlength="11"
|
||||
disabled="{{isJoining}}"
|
||||
/>
|
||||
<input
|
||||
wx:else
|
||||
type="text"
|
||||
class="form-input"
|
||||
placeholder="请输入微信号"
|
||||
placeholder-class="input-placeholder"
|
||||
value="{{wechatId}}"
|
||||
bindinput="onWechatInput"
|
||||
disabled="{{isJoining}}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<text class="error-text" wx:if="{{joinError}}">{{joinError}}</text>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<view
|
||||
class="btn-primary submit-btn {{isJoining || !(contactType === 'phone' ? phoneNumber : wechatId) ? 'btn-disabled' : ''}}"
|
||||
bindtap="handleJoinSubmit"
|
||||
>
|
||||
<text wx:if="{{isJoining}}">提交中...</text>
|
||||
<text wx:else>确认加入</text>
|
||||
</view>
|
||||
|
||||
<text class="form-notice">提交即表示同意我们的服务条款</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近匹配记录 -->
|
||||
<view class="recent-matches" wx:if="{{recentMatches.length > 0 && !isMatching}}">
|
||||
<view class="section-title">最近匹配</view>
|
||||
<scroll-view class="matches-scroll" scroll-x>
|
||||
<view class="match-item" wx:for="{{recentMatches}}" wx:key="id" bindtap="viewMatchDetail" data-id="{{item.id}}">
|
||||
<image class="match-avatar" src="{{item.avatar}}" mode="aspectFill"></image>
|
||||
<view class="match-name">{{item.nickname}}</view>
|
||||
<view class="match-time">{{item.matchTime}}</view>
|
||||
<!-- 解锁弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showUnlockModal}}" bindtap="closeUnlockModal">
|
||||
<view class="modal-content unlock-modal" catchtap="preventBubble">
|
||||
<view class="unlock-icon">⚡</view>
|
||||
<text class="unlock-title">匹配机会已用完</text>
|
||||
<text class="unlock-desc">每购买一个小节内容即可额外获得1次匹配机会</text>
|
||||
|
||||
<view class="unlock-info">
|
||||
<view class="info-row">
|
||||
<text class="info-label">解锁方式</text>
|
||||
<text class="info-value">购买任意小节</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">获得次数</text>
|
||||
<text class="info-value text-brand">+1次匹配</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="unlock-buttons">
|
||||
<view class="btn-gold" bindtap="goToChapters">去购买小节 (¥1/节)</view>
|
||||
<view class="btn-ghost" bindtap="closeUnlockModal">明天再来</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部留白 -->
|
||||
<view class="bottom-space"></view>
|
||||
</view>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,452 +1,228 @@
|
||||
// pages/my/my.js
|
||||
/**
|
||||
* Soul创业实验 - 我的页面
|
||||
* 开发: 卡若
|
||||
* 技术支持: 存客宝
|
||||
*/
|
||||
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
userInfo: {},
|
||||
userStats: {
|
||||
readChapters: 0,
|
||||
readMinutes: 0,
|
||||
bookmarks: 0
|
||||
},
|
||||
earnings: {
|
||||
total: '0.00',
|
||||
available: '0.00',
|
||||
withdrawn: '0.00'
|
||||
},
|
||||
referralData: {
|
||||
totalUsers: 0,
|
||||
totalOrders: 0,
|
||||
commissionRate: 90
|
||||
},
|
||||
menuBadges: {
|
||||
orders: 0
|
||||
},
|
||||
showPoster: false
|
||||
// 系统信息
|
||||
statusBarHeight: 44,
|
||||
navBarHeight: 88,
|
||||
|
||||
// 用户状态
|
||||
isLoggedIn: false,
|
||||
userInfo: null,
|
||||
|
||||
// 统计数据
|
||||
totalSections: 62,
|
||||
purchasedCount: 0,
|
||||
referralCount: 0,
|
||||
earnings: 0,
|
||||
pendingEarnings: 0,
|
||||
|
||||
// 阅读统计
|
||||
totalReadTime: 0,
|
||||
matchHistory: 0,
|
||||
|
||||
// Tab切换
|
||||
activeTab: 'overview', // overview | footprint
|
||||
|
||||
// 最近阅读
|
||||
recentChapters: [],
|
||||
|
||||
// 菜单列表
|
||||
menuList: [
|
||||
{ id: 'orders', title: '我的订单', icon: '📦', count: 0 },
|
||||
{ id: 'referral', title: '推广中心', icon: '🎁', badge: '90%佣金' },
|
||||
{ id: 'about', title: '关于作者', icon: '👤', iconBg: 'brand' },
|
||||
{ id: 'settings', title: '设置', icon: '⚙️', iconBg: 'gray' }
|
||||
],
|
||||
|
||||
// 登录弹窗
|
||||
showLoginModal: false,
|
||||
isLoggingIn: false
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 检查是否有tab参数
|
||||
if (options.tab === 'referral') {
|
||||
// 自动展开分销中心
|
||||
this.setData({ expandReferral: true })
|
||||
}
|
||||
onLoad() {
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight,
|
||||
navBarHeight: app.globalData.navBarHeight
|
||||
})
|
||||
this.initUserStatus()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.loadUserInfo()
|
||||
this.loadUserStats()
|
||||
this.loadEarnings()
|
||||
this.loadReferralData()
|
||||
},
|
||||
|
||||
// 加载用户信息
|
||||
loadUserInfo() {
|
||||
const userInfo = app.getUserInfo()
|
||||
|
||||
if (userInfo) {
|
||||
this.setData({ userInfo })
|
||||
} else {
|
||||
// 未登录状态
|
||||
this.setData({
|
||||
userInfo: {
|
||||
avatar: '',
|
||||
nickname: '点击登录',
|
||||
id: '',
|
||||
inviteCode: ''
|
||||
}
|
||||
})
|
||||
// 设置TabBar选中状态
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
this.getTabBar().setData({ selected: 3 })
|
||||
}
|
||||
this.initUserStatus()
|
||||
},
|
||||
|
||||
// 加载用户统计
|
||||
loadUserStats() {
|
||||
const token = wx.getStorageSync('token')
|
||||
if (!token) return
|
||||
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/user/stats`,
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
this.setData({
|
||||
userStats: res.data.stats
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 使用缓存数据
|
||||
const cached = wx.getStorageSync('userStats')
|
||||
if (cached) {
|
||||
this.setData({ userStats: cached })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 加载收益数据
|
||||
loadEarnings() {
|
||||
const token = wx.getStorageSync('token')
|
||||
if (!token) return
|
||||
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/referral/earnings`,
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
this.setData({
|
||||
earnings: {
|
||||
total: res.data.total || '0.00',
|
||||
available: res.data.available || '0.00',
|
||||
withdrawn: res.data.withdrawn || '0.00'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 加载推广数据
|
||||
loadReferralData() {
|
||||
const token = wx.getStorageSync('token')
|
||||
if (!token) return
|
||||
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/referral/stats`,
|
||||
header: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
this.setData({
|
||||
referralData: res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 编辑资料
|
||||
editProfile() {
|
||||
const userInfo = this.data.userInfo
|
||||
// 初始化用户状态
|
||||
initUserStatus() {
|
||||
const { isLoggedIn, userInfo, hasFullBook, purchasedSections } = app.globalData
|
||||
|
||||
if (!userInfo.id) {
|
||||
// 未登录,执行登录
|
||||
this.doLogin()
|
||||
return
|
||||
}
|
||||
|
||||
wx.navigateTo({
|
||||
url: '/pages/profile/edit'
|
||||
})
|
||||
},
|
||||
|
||||
// 执行登录
|
||||
doLogin() {
|
||||
wx.showLoading({ title: '登录中...', mask: true })
|
||||
|
||||
app.wxLogin((success, user) => {
|
||||
wx.hideLoading()
|
||||
if (isLoggedIn && userInfo) {
|
||||
// 转换为对象数组
|
||||
const recentList = (purchasedSections || []).slice(-5).map(id => ({
|
||||
id: id,
|
||||
title: `章节 ${id}`
|
||||
}))
|
||||
|
||||
if (success) {
|
||||
wx.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
this.setData({ userInfo: user })
|
||||
this.loadUserStats()
|
||||
this.loadEarnings()
|
||||
this.loadReferralData()
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '登录失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 生成推广海报
|
||||
generatePoster() {
|
||||
const userInfo = this.data.userInfo
|
||||
|
||||
if (!userInfo.id) {
|
||||
this.showLoginModal()
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({ showPoster: true })
|
||||
|
||||
wx.showLoading({ title: '生成中...', mask: true })
|
||||
|
||||
// 使用Canvas绘制海报
|
||||
setTimeout(() => {
|
||||
this.drawPoster()
|
||||
wx.hideLoading()
|
||||
}, 500)
|
||||
},
|
||||
|
||||
// 绘制海报
|
||||
drawPoster() {
|
||||
const ctx = wx.createCanvasContext('posterCanvas')
|
||||
const userInfo = this.data.userInfo
|
||||
|
||||
// 背景
|
||||
ctx.setFillStyle('#000000')
|
||||
ctx.fillRect(0, 0, 375, 500)
|
||||
|
||||
// 渐变背景
|
||||
const gradient = ctx.createLinearGradient(0, 0, 0, 500)
|
||||
gradient.addColorStop(0, 'rgba(255, 77, 79, 0.3)')
|
||||
gradient.addColorStop(1, 'rgba(0, 0, 0, 0)')
|
||||
ctx.setFillStyle(gradient)
|
||||
ctx.fillRect(0, 0, 375, 500)
|
||||
|
||||
// 标题
|
||||
ctx.setFontSize(32)
|
||||
ctx.setFillStyle('#FFFFFF')
|
||||
ctx.setTextAlign('center')
|
||||
ctx.fillText('Soul派对·创业实验', 187.5, 60)
|
||||
|
||||
// 邀请码
|
||||
ctx.setFontSize(48)
|
||||
ctx.setFillStyle('#FF4D4F')
|
||||
ctx.fillText(userInfo.inviteCode || 'XXXXXX', 187.5, 250)
|
||||
|
||||
// 提示文字
|
||||
ctx.setFontSize(24)
|
||||
ctx.setFillStyle('rgba(255, 255, 255, 0.8)')
|
||||
ctx.fillText('使用此邀请码购买,双方都有佣金!', 187.5, 320)
|
||||
|
||||
// 二维码占位
|
||||
ctx.setStrokeStyle('#FFFFFF')
|
||||
ctx.strokeRect(137.5, 360, 100, 100)
|
||||
ctx.setFontSize(16)
|
||||
ctx.setFillStyle('rgba(255, 255, 255, 0.5)')
|
||||
ctx.fillText('扫码阅读', 187.5, 420)
|
||||
|
||||
ctx.draw()
|
||||
},
|
||||
|
||||
// 关闭海报
|
||||
closePoster() {
|
||||
this.setData({ showPoster: false })
|
||||
},
|
||||
|
||||
// 阻止冒泡
|
||||
stopPropagation() {},
|
||||
|
||||
// 保存海报
|
||||
savePoster() {
|
||||
wx.canvasToTempFilePath({
|
||||
canvasId: 'posterCanvas',
|
||||
success: (res) => {
|
||||
wx.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
wx.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
})
|
||||
this.closePoster()
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '保存失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 提现
|
||||
withdraw() {
|
||||
const earnings = this.data.earnings
|
||||
const available = parseFloat(earnings.available)
|
||||
|
||||
if (available < 1) {
|
||||
wx.showToast({
|
||||
title: '可提现金额不足1元',
|
||||
icon: 'none'
|
||||
this.setData({
|
||||
isLoggedIn: true,
|
||||
userInfo,
|
||||
purchasedCount: hasFullBook ? this.data.totalSections : (purchasedSections?.length || 0),
|
||||
referralCount: userInfo.referralCount || 0,
|
||||
earnings: userInfo.earnings || 0,
|
||||
pendingEarnings: userInfo.pendingEarnings || 0,
|
||||
recentChapters: recentList,
|
||||
totalReadTime: Math.floor(Math.random() * 200) + 50
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/withdraw/withdraw?amount=${available}`
|
||||
})
|
||||
},
|
||||
|
||||
// 复制邀请码
|
||||
copyInviteCode() {
|
||||
const inviteCode = this.data.userInfo.inviteCode
|
||||
|
||||
if (!inviteCode) {
|
||||
wx.showToast({
|
||||
title: '请先登录',
|
||||
icon: 'none'
|
||||
} else {
|
||||
this.setData({
|
||||
isLoggedIn: false,
|
||||
userInfo: null,
|
||||
purchasedCount: 0,
|
||||
referralCount: 0,
|
||||
earnings: 0,
|
||||
pendingEarnings: 0,
|
||||
recentChapters: []
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wx.setClipboardData({
|
||||
data: inviteCode,
|
||||
success: () => {
|
||||
wx.showToast({
|
||||
title: '已复制邀请码',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 查看推荐列表
|
||||
viewReferrals() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/referral/list'
|
||||
})
|
||||
},
|
||||
|
||||
// 查看订单列表
|
||||
viewOrders() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/referral/orders'
|
||||
})
|
||||
},
|
||||
|
||||
// 查看佣金明细
|
||||
viewCommission() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/referral/commission'
|
||||
})
|
||||
},
|
||||
|
||||
// 我的订单
|
||||
goToOrders() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/orders/list'
|
||||
})
|
||||
},
|
||||
|
||||
// 阅读历史
|
||||
goToReadHistory() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/history/read'
|
||||
})
|
||||
},
|
||||
|
||||
// 阅读时长
|
||||
goToReadTime() {
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
// 书签
|
||||
goToBookmarks() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/bookmarks/list'
|
||||
})
|
||||
},
|
||||
|
||||
// 阅读笔记
|
||||
goToNotes() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/notes/list'
|
||||
})
|
||||
},
|
||||
|
||||
// 设置
|
||||
goToSettings() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/settings/index'
|
||||
})
|
||||
},
|
||||
|
||||
// 联系客服
|
||||
contactSupport() {
|
||||
wx.showToast({
|
||||
title: '客服功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
// 关于我们
|
||||
about() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/about/index'
|
||||
})
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
logout() {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.removeStorageSync('token')
|
||||
wx.removeStorageSync('userInfo')
|
||||
app.globalData.userInfo = null
|
||||
|
||||
this.setData({
|
||||
userInfo: {
|
||||
avatar: '',
|
||||
nickname: '点击登录',
|
||||
id: '',
|
||||
inviteCode: ''
|
||||
},
|
||||
earnings: {
|
||||
total: '0.00',
|
||||
available: '0.00',
|
||||
withdrawn: '0.00'
|
||||
},
|
||||
referralData: {
|
||||
totalUsers: 0,
|
||||
totalOrders: 0,
|
||||
commissionRate: 90
|
||||
}
|
||||
})
|
||||
|
||||
wx.showToast({
|
||||
title: '已退出登录',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
// 切换Tab
|
||||
switchTab(e) {
|
||||
const tab = e.currentTarget.dataset.tab
|
||||
this.setData({ activeTab: tab })
|
||||
},
|
||||
|
||||
// 显示登录弹窗
|
||||
showLoginModal() {
|
||||
showLogin() {
|
||||
this.setData({ showLoginModal: true })
|
||||
},
|
||||
|
||||
// 关闭登录弹窗
|
||||
closeLoginModal() {
|
||||
if (this.data.isLoggingIn) return
|
||||
this.setData({ showLoginModal: false })
|
||||
},
|
||||
|
||||
// 微信登录
|
||||
async handleWechatLogin() {
|
||||
this.setData({ isLoggingIn: true })
|
||||
|
||||
try {
|
||||
const result = await app.login()
|
||||
if (result) {
|
||||
this.initUserStatus()
|
||||
this.setData({ showLoginModal: false })
|
||||
wx.showToast({ title: '登录成功', icon: 'success' })
|
||||
} else {
|
||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('微信登录错误:', e)
|
||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
} finally {
|
||||
this.setData({ isLoggingIn: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 手机号登录(需要用户授权)
|
||||
async handlePhoneLogin(e) {
|
||||
// 检查是否有授权code
|
||||
if (!e.detail.code) {
|
||||
// 用户拒绝授权或获取失败,尝试使用微信登录
|
||||
console.log('手机号授权失败,尝试微信登录')
|
||||
return this.handleWechatLogin()
|
||||
}
|
||||
|
||||
this.setData({ isLoggingIn: true })
|
||||
|
||||
try {
|
||||
const result = await app.loginWithPhone(e.detail.code)
|
||||
if (result) {
|
||||
this.initUserStatus()
|
||||
this.setData({ showLoginModal: false })
|
||||
wx.showToast({ title: '登录成功', icon: 'success' })
|
||||
} else {
|
||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('手机号登录错误:', e)
|
||||
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
|
||||
} finally {
|
||||
this.setData({ isLoggingIn: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 点击菜单
|
||||
handleMenuTap(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
|
||||
if (!this.data.isLoggedIn && id !== 'about') {
|
||||
this.showLogin()
|
||||
return
|
||||
}
|
||||
|
||||
const routes = {
|
||||
orders: '/pages/purchases/purchases',
|
||||
referral: '/pages/referral/referral',
|
||||
about: '/pages/about/about',
|
||||
settings: '/pages/settings/settings'
|
||||
}
|
||||
|
||||
if (routes[id]) {
|
||||
wx.navigateTo({ url: routes[id] })
|
||||
}
|
||||
},
|
||||
|
||||
// 跳转到阅读页
|
||||
goToRead(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
wx.navigateTo({ url: `/pages/read/read?id=${id}` })
|
||||
},
|
||||
|
||||
// 跳转到目录
|
||||
goToChapters() {
|
||||
wx.switchTab({ url: '/pages/chapters/chapters' })
|
||||
},
|
||||
|
||||
// 跳转到匹配
|
||||
goToMatch() {
|
||||
wx.switchTab({ url: '/pages/match/match' })
|
||||
},
|
||||
|
||||
// 跳转到推广中心
|
||||
goToReferral() {
|
||||
if (!this.data.isLoggedIn) {
|
||||
this.showLogin()
|
||||
return
|
||||
}
|
||||
wx.navigateTo({ url: '/pages/referral/referral' })
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
handleLogout() {
|
||||
wx.showModal({
|
||||
title: '需要登录',
|
||||
content: '请先登录账号',
|
||||
confirmText: '立即登录',
|
||||
title: '退出登录',
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.doLogin()
|
||||
app.logout()
|
||||
this.initUserStatus()
|
||||
wx.showToast({ title: '已退出登录', icon: 'success' })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.loadUserInfo()
|
||||
this.loadUserStats()
|
||||
this.loadEarnings()
|
||||
this.loadReferralData()
|
||||
|
||||
setTimeout(() => {
|
||||
wx.stopPullDownRefresh()
|
||||
}, 1000)
|
||||
}
|
||||
// 阻止冒泡
|
||||
stopPropagation() {}
|
||||
})
|
||||
|
||||
6
miniprogram/pages/my/my.json
Normal file
6
miniprogram/pages/my/my.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundTextStyle": "light",
|
||||
"backgroundColor": "#000000"
|
||||
}
|
||||
@@ -1,204 +1,231 @@
|
||||
<!--pages/my/my.wxml-->
|
||||
<view class="container my-container page-transition">
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-card glass-effect">
|
||||
<!--Soul创业实验 - 我的页面 1:1还原Web版本-->
|
||||
<view class="page page-transition">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-content">
|
||||
<text class="nav-title brand-color">我的</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 导航栏占位 -->
|
||||
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<!-- 用户卡片 - 未登录状态 -->
|
||||
<view class="user-card card-gradient" wx:if="{{!isLoggedIn}}">
|
||||
<view class="user-header">
|
||||
<image
|
||||
class="user-avatar"
|
||||
src="{{userInfo.avatar || '/assets/images/default-avatar.png'}}"
|
||||
mode="aspectFill"
|
||||
bindtap="editProfile"
|
||||
></image>
|
||||
<view class="avatar avatar-empty">
|
||||
<text class="avatar-icon">👤</text>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<view class="user-name">{{userInfo.nickname || '点击登录'}}</view>
|
||||
<view class="user-id">ID: {{userInfo.id || '---'}}</view>
|
||||
</view>
|
||||
<view class="vip-badge" wx:if="{{userInfo.isPurchased}}">
|
||||
<text class="vip-text">已购</text>
|
||||
<view class="login-btn" bindtap="showLogin">点击登录</view>
|
||||
<text class="user-subtitle">解锁专属权益</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="stats-grid">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value brand-color">0</text>
|
||||
<text class="stat-label">已购章节</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value brand-color">0</text>
|
||||
<text class="stat-label">推荐好友</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value gold-color">--</text>
|
||||
<text class="stat-label">待领收益</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户卡片 - 已登录状态 -->
|
||||
<view class="user-card card-gradient" wx:else>
|
||||
<view class="user-header">
|
||||
<view class="avatar">
|
||||
<text class="avatar-text">{{userInfo.nickname[0] || 'U'}}</text>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<text class="user-name">{{userInfo.nickname || '用户'}}</text>
|
||||
<text class="user-id">ID: {{userInfo.id}}</text>
|
||||
</view>
|
||||
<view class="user-badge">
|
||||
<text class="badge-icon">⭐</text>
|
||||
<text class="badge-text">创业伙伴</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="stats-grid">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value brand-color">{{purchasedCount}}</text>
|
||||
<text class="stat-label">已购章节</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value brand-color">{{referralCount}}</text>
|
||||
<text class="stat-label">推荐好友</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value gold-color">{{earnings > 0 ? '¥' + earnings : '--'}}</text>
|
||||
<text class="stat-label">待领收益</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 推广入口 - 未登录 -->
|
||||
<view class="referral-card" wx:if="{{!isLoggedIn}}" bindtap="showLogin">
|
||||
<view class="referral-left">
|
||||
<view class="referral-icon gold-bg">🎁</view>
|
||||
<view class="referral-info">
|
||||
<text class="referral-title">推广赚收益</text>
|
||||
<text class="referral-desc">登录后查看详情</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="referral-btn">立即登录</view>
|
||||
</view>
|
||||
|
||||
<!-- Tab切换 -->
|
||||
<view class="tab-bar-custom" wx:if="{{isLoggedIn}}">
|
||||
<view
|
||||
class="tab-item {{activeTab === 'overview' ? 'tab-active' : ''}}"
|
||||
bindtap="switchTab"
|
||||
data-tab="overview"
|
||||
>概览</view>
|
||||
<view
|
||||
class="tab-item {{activeTab === 'footprint' ? 'tab-active' : ''}}"
|
||||
bindtap="switchTab"
|
||||
data-tab="footprint"
|
||||
>
|
||||
<text class="tab-icon">👣</text>
|
||||
<text>我的足迹</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 概览内容 -->
|
||||
<view class="tab-content" wx:if="{{activeTab === 'overview'}}">
|
||||
<!-- 菜单列表 -->
|
||||
<view class="menu-card card">
|
||||
<view
|
||||
class="menu-item"
|
||||
wx:for="{{menuList}}"
|
||||
wx:key="id"
|
||||
bindtap="handleMenuTap"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="menu-left">
|
||||
<view class="menu-icon {{item.iconBg === 'brand' ? 'icon-brand' : item.iconBg === 'gray' ? 'icon-gray' : ''}}">
|
||||
{{item.icon}}
|
||||
</view>
|
||||
<text class="menu-title">{{item.title}}</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-count" wx:if="{{item.count !== undefined}}">{{item.count}}笔</text>
|
||||
<text class="menu-badge gold-color" wx:if="{{item.badge}}">{{item.badge}}</text>
|
||||
<text class="menu-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 足迹内容 -->
|
||||
<view class="tab-content" wx:if="{{activeTab === 'footprint' && isLoggedIn}}">
|
||||
<!-- 阅读统计 -->
|
||||
<view class="user-stats">
|
||||
<view class="stat-item" bindtap="goToReadHistory">
|
||||
<view class="stat-value">{{userStats.readChapters}}</view>
|
||||
<view class="stat-label">已读章节</view>
|
||||
<view class="stats-card card">
|
||||
<view class="card-title">
|
||||
<text class="title-icon">👁️</text>
|
||||
<text>阅读统计</text>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item" bindtap="goToReadTime">
|
||||
<view class="stat-value">{{userStats.readMinutes}}</view>
|
||||
<view class="stat-label">阅读时长(分)</view>
|
||||
<view class="stats-row">
|
||||
<view class="stat-box">
|
||||
<text class="stat-icon brand-color">📖</text>
|
||||
<text class="stat-num">{{purchasedCount}}</text>
|
||||
<text class="stat-text">已读章节</text>
|
||||
</view>
|
||||
<view class="stat-box">
|
||||
<text class="stat-icon gold-color">⏱️</text>
|
||||
<text class="stat-num">{{totalReadTime}}</text>
|
||||
<text class="stat-text">阅读分钟</text>
|
||||
</view>
|
||||
<view class="stat-box">
|
||||
<text class="stat-icon pink-color">👥</text>
|
||||
<text class="stat-num">{{matchHistory}}</text>
|
||||
<text class="stat-text">匹配伙伴</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-item" bindtap="goToBookmarks">
|
||||
<view class="stat-value">{{userStats.bookmarks}}</view>
|
||||
<view class="stat-label">书签</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近阅读 -->
|
||||
<view class="recent-card card">
|
||||
<view class="card-title">
|
||||
<text class="title-icon">📖</text>
|
||||
<text>最近阅读</text>
|
||||
</view>
|
||||
<view class="recent-list" wx:if="{{recentChapters.length > 0}}">
|
||||
<view
|
||||
class="recent-item"
|
||||
wx:for="{{recentChapters}}"
|
||||
wx:key="id"
|
||||
bindtap="goToRead"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="recent-left">
|
||||
<text class="recent-index">{{index + 1}}</text>
|
||||
<text class="recent-title">{{item.title}}</text>
|
||||
</view>
|
||||
<text class="recent-btn">继续阅读</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty-state" wx:else>
|
||||
<text class="empty-icon">📖</text>
|
||||
<text class="empty-text">暂无阅读记录</text>
|
||||
<view class="empty-btn" bindtap="goToChapters">去阅读 →</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 匹配记录 -->
|
||||
<view class="match-card card">
|
||||
<view class="card-title">
|
||||
<text class="title-icon">👥</text>
|
||||
<text>匹配记录</text>
|
||||
</view>
|
||||
<view class="empty-state">
|
||||
<text class="empty-icon">👥</text>
|
||||
<text class="empty-text">暂无匹配记录</text>
|
||||
<view class="empty-btn" bindtap="goToMatch">去匹配 →</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分销中心(重点功能) -->
|
||||
<view class="referral-section card">
|
||||
<view class="section-header">
|
||||
<view class="section-title">
|
||||
<text class="title-icon">💰</text>
|
||||
<text class="title-text">分销中心</text>
|
||||
</view>
|
||||
<view class="referral-status">
|
||||
<text class="status-text">佣金比例:</text>
|
||||
<text class="status-value">90%</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 收益概览 -->
|
||||
<view class="earnings-overview">
|
||||
<view class="earnings-main">
|
||||
<view class="earnings-label">累计收益</view>
|
||||
<view class="earnings-amount">¥{{earnings.total}}</view>
|
||||
</view>
|
||||
<view class="earnings-sub">
|
||||
<view class="sub-item">
|
||||
<text class="sub-label">可提现</text>
|
||||
<text class="sub-value brand-color">¥{{earnings.available}}</text>
|
||||
</view>
|
||||
<view class="sub-item">
|
||||
<text class="sub-label">已提现</text>
|
||||
<text class="sub-value">¥{{earnings.withdrawn}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快速操作 -->
|
||||
<view class="referral-actions">
|
||||
<button class="btn-primary action-btn" bindtap="generatePoster">
|
||||
生成推广海报
|
||||
<!-- 登录弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showLoginModal}}" bindtap="closeLoginModal">
|
||||
<view class="modal-content" catchtap="stopPropagation">
|
||||
<view class="modal-close" bindtap="closeLoginModal">✕</view>
|
||||
<view class="login-icon">🔐</view>
|
||||
<text class="login-title">登录 Soul创业实验</text>
|
||||
<text class="login-desc">登录后可购买章节、参与匹配、赚取佣金</text>
|
||||
|
||||
<button
|
||||
class="btn-wechat"
|
||||
bindtap="handleWechatLogin"
|
||||
disabled="{{isLoggingIn}}"
|
||||
>
|
||||
<text class="btn-wechat-icon">微</text>
|
||||
<text>{{isLoggingIn ? '登录中...' : '微信快捷登录'}}</text>
|
||||
</button>
|
||||
<button class="btn-secondary action-btn" bindtap="withdraw">
|
||||
立即提现
|
||||
|
||||
<button
|
||||
class="btn-phone"
|
||||
open-type="getPhoneNumber"
|
||||
bindgetphonenumber="handlePhoneLogin"
|
||||
disabled="{{isLoggingIn}}"
|
||||
>
|
||||
<text class="btn-phone-icon">📱</text>
|
||||
<text>手机号登录</text>
|
||||
</button>
|
||||
|
||||
<text class="login-notice">登录即表示同意《用户协议》和《隐私政策》</text>
|
||||
</view>
|
||||
|
||||
<!-- 推广数据 -->
|
||||
<view class="referral-stats">
|
||||
<view class="referral-stat-item" bindtap="viewReferrals">
|
||||
<view class="stat-number">{{referralData.totalUsers}}</view>
|
||||
<view class="stat-name">推荐人数</view>
|
||||
</view>
|
||||
<view class="referral-stat-item" bindtap="viewOrders">
|
||||
<view class="stat-number">{{referralData.totalOrders}}</view>
|
||||
<view class="stat-name">成交订单</view>
|
||||
</view>
|
||||
<view class="referral-stat-item" bindtap="viewCommission">
|
||||
<view class="stat-number">{{referralData.commissionRate}}%</view>
|
||||
<view class="stat-name">佣金率</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的邀请码 -->
|
||||
<view class="invite-code-section">
|
||||
<view class="invite-label">我的邀请码</view>
|
||||
<view class="invite-code-box">
|
||||
<text class="invite-code">{{userInfo.inviteCode || '---'}}</text>
|
||||
<button class="copy-btn" bindtap="copyInviteCode">复制</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="menu-section">
|
||||
<view class="menu-group card">
|
||||
<view class="menu-item" bindtap="goToOrders">
|
||||
<view class="menu-left">
|
||||
<text class="menu-icon">📦</text>
|
||||
<text class="menu-text">我的订单</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-badge" wx:if="{{menuBadges.orders > 0}}">{{menuBadges.orders}}</text>
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-divider"></view>
|
||||
|
||||
<view class="menu-item" bindtap="goToBookmarks">
|
||||
<view class="menu-left">
|
||||
<text class="menu-icon">🔖</text>
|
||||
<text class="menu-text">我的书签</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-divider"></view>
|
||||
|
||||
<view class="menu-item" bindtap="goToNotes">
|
||||
<view class="menu-left">
|
||||
<text class="menu-icon">📝</text>
|
||||
<text class="menu-text">阅读笔记</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-group card">
|
||||
<view class="menu-item" bindtap="goToSettings">
|
||||
<view class="menu-left">
|
||||
<text class="menu-icon">⚙️</text>
|
||||
<text class="menu-text">设置</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-divider"></view>
|
||||
|
||||
<view class="menu-item" bindtap="contactSupport">
|
||||
<view class="menu-left">
|
||||
<text class="menu-icon">💬</text>
|
||||
<text class="menu-text">联系客服</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-divider"></view>
|
||||
|
||||
<view class="menu-item" bindtap="about">
|
||||
<view class="menu-left">
|
||||
<text class="menu-icon">ℹ️</text>
|
||||
<text class="menu-text">关于我们</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-arrow">></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录 -->
|
||||
<view class="logout-section" wx:if="{{userInfo.id}}">
|
||||
<button class="logout-btn" bindtap="logout">退出登录</button>
|
||||
</view>
|
||||
|
||||
<!-- 底部留白 -->
|
||||
<view class="bottom-space"></view>
|
||||
</view>
|
||||
|
||||
<!-- 海报生成弹窗 -->
|
||||
<view class="poster-modal" wx:if="{{showPoster}}" bindtap="closePoster">
|
||||
<view class="poster-content" catchtap="stopPropagation">
|
||||
<view class="poster-header">
|
||||
<text class="poster-title">长按保存海报</text>
|
||||
<text class="poster-close" bindtap="closePoster">×</text>
|
||||
</view>
|
||||
<canvas canvas-id="posterCanvas" class="poster-canvas"></canvas>
|
||||
<button class="btn-primary save-poster-btn" bindtap="savePoster">
|
||||
保存到相册
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,284 +1,418 @@
|
||||
/* pages/my/my.wxss */
|
||||
/**
|
||||
* Soul创业实验 - 我的页面样式
|
||||
* 1:1还原Web版本UI
|
||||
*/
|
||||
|
||||
.my-container {
|
||||
padding: 32rpx 32rpx 160rpx;
|
||||
background: linear-gradient(180deg, #000000 0%, #0a0a0a 100%);
|
||||
.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);
|
||||
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;
|
||||
}
|
||||
|
||||
.gold-color {
|
||||
color: #FFD700;
|
||||
}
|
||||
|
||||
.pink-color {
|
||||
color: #E91E63;
|
||||
}
|
||||
|
||||
.nav-placeholder {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ===== 用户卡片 ===== */
|
||||
.user-card {
|
||||
padding: 40rpx 32rpx;
|
||||
margin-bottom: 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);
|
||||
}
|
||||
|
||||
.user-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
margin-right: 24rpx;
|
||||
border: 4rpx solid rgba(255, 77, 79, 0.5);
|
||||
.avatar {
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
border-radius: 50%;
|
||||
border: 4rpx solid #00CED1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, rgba(0, 206, 209, 0.2) 0%, transparent 100%);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.avatar-empty {
|
||||
border-style: dashed;
|
||||
border-color: rgba(0, 206, 209, 0.5);
|
||||
}
|
||||
|
||||
.avatar-icon {
|
||||
font-size: 64rpx;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
font-size: 48rpx;
|
||||
font-weight: 700;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.user-subtitle {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
display: block;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
margin-bottom: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.user-id {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
display: block;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.vip-badge {
|
||||
.user-badge {
|
||||
padding: 8rpx 20rpx;
|
||||
background: linear-gradient(135deg, #FF4D4F 0%, #FF7875 100%);
|
||||
border-radius: 20rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(255, 77, 79, 0.4);
|
||||
}
|
||||
|
||||
.vip-text {
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 用户统计 */
|
||||
.user-stats {
|
||||
background: rgba(0, 206, 209, 0.2);
|
||||
border: 2rpx solid rgba(0, 206, 209, 0.3);
|
||||
border-radius: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.badge-icon {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.badge-text {
|
||||
font-size: 22rpx;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16rpx;
|
||||
padding-top: 32rpx;
|
||||
border-top: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 16rpx;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #FF4D4F;
|
||||
margin-bottom: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
width: 2rpx;
|
||||
height: 60rpx;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* 分销中心 */
|
||||
.referral-section {
|
||||
margin-bottom: 24rpx;
|
||||
/* ===== 收益卡片 ===== */
|
||||
.earnings-card {
|
||||
margin: 32rpx;
|
||||
padding: 32rpx;
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||||
border-radius: 32rpx;
|
||||
border: 2rpx solid rgba(0, 206, 209, 0.2);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
.earnings-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 256rpx;
|
||||
height: 256rpx;
|
||||
background: linear-gradient(135deg, rgba(255, 215, 0, 0.1) 0%, transparent 100%);
|
||||
border-radius: 50%;
|
||||
transform: translate(50%, -50%);
|
||||
}
|
||||
|
||||
.earnings-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.earnings-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
.earnings-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
font-size: 32rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.referral-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
background: rgba(255, 77, 79, 0.2);
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.status-value {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #FF4D4F;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
/* 收益概览 */
|
||||
.earnings-overview {
|
||||
padding: 32rpx;
|
||||
background: rgba(255, 77, 79, 0.1);
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid rgba(255, 77, 79, 0.2);
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.earnings-main {
|
||||
text-align: center;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.earnings-label {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.earnings-amount {
|
||||
font-size: 64rpx;
|
||||
font-weight: 700;
|
||||
color: #FF4D4F;
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
|
||||
.earnings-sub {
|
||||
.earnings-link {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding-top: 24rpx;
|
||||
border-top: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.sub-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.sub-label {
|
||||
.link-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
.sub-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
.link-arrow {
|
||||
font-size: 24rpx;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
/* 快速操作 */
|
||||
.referral-actions {
|
||||
.earnings-data {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
align-items: flex-end;
|
||||
gap: 48rpx;
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
/* 推广数据 */
|
||||
.referral-stats {
|
||||
.data-item {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 32rpx 0;
|
||||
border-top: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
border-bottom: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
margin-bottom: 24rpx;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.referral-stat-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #FF4D4F;
|
||||
.data-label {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-name {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
/* 邀请码 */
|
||||
.invite-code-section {
|
||||
padding: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.invite-label {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.invite-code-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.invite-code {
|
||||
.data-value {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #FF4D4F;
|
||||
letter-spacing: 4rpx;
|
||||
font-family: 'Courier New', monospace;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
padding: 12rpx 32rpx;
|
||||
background: rgba(255, 77, 79, 0.2);
|
||||
color: #FF7875;
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
font-size: 26rpx;
|
||||
.gold-gradient {
|
||||
background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-size: 56rpx;
|
||||
}
|
||||
|
||||
.earnings-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16rpx;
|
||||
padding: 24rpx;
|
||||
background: linear-gradient(135deg, rgba(255, 215, 0, 0.8) 0%, rgba(255, 165, 0, 0.8) 100%);
|
||||
border-radius: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 功能菜单 */
|
||||
.menu-section {
|
||||
margin-bottom: 24rpx;
|
||||
.btn-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.menu-group {
|
||||
.btn-text {
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* ===== 推广入口 ===== */
|
||||
.referral-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 32rpx;
|
||||
padding: 32rpx;
|
||||
background: linear-gradient(90deg, rgba(255, 215, 0, 0.1) 0%, #1c1c1e 100%);
|
||||
border: 2rpx solid rgba(255, 215, 0, 0.2);
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
|
||||
.referral-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.referral-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.gold-bg {
|
||||
background: linear-gradient(135deg, #FFD700 0%, #FFA500 100%);
|
||||
}
|
||||
|
||||
.referral-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.referral-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.referral-desc {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.referral-btn {
|
||||
padding: 16rpx 32rpx;
|
||||
background: rgba(255, 215, 0, 0.2);
|
||||
color: #FFD700;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
/* ===== Tab切换 ===== */
|
||||
.tab-bar-custom {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
margin: 32rpx;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
background: #1c1c1e;
|
||||
border-radius: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.tab-active {
|
||||
background: rgba(0, 206, 209, 0.2);
|
||||
color: #00CED1;
|
||||
border: 2rpx solid rgba(0, 206, 209, 0.3);
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* ===== Tab内容 ===== */
|
||||
.tab-content {
|
||||
padding: 0 32rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ===== 菜单卡片 ===== */
|
||||
.card {
|
||||
background: #1c1c1e;
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.05);
|
||||
overflow: hidden;
|
||||
margin: 0 0 24rpx 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.menu-card {
|
||||
padding: 0;
|
||||
margin-bottom: 24rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 32rpx;
|
||||
transition: background 0.3s;
|
||||
justify-content: space-between;
|
||||
padding: 28rpx 32rpx;
|
||||
border-bottom: 1rpx solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
@@ -288,15 +422,30 @@
|
||||
.menu-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
font-size: 40rpx;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
font-size: 30rpx;
|
||||
.icon-brand {
|
||||
background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
|
||||
}
|
||||
|
||||
.icon-gray {
|
||||
background: rgba(128, 128, 128, 0.2);
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
@@ -306,17 +455,14 @@
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.menu-count {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.menu-badge {
|
||||
min-width: 32rpx;
|
||||
height: 32rpx;
|
||||
padding: 0 8rpx;
|
||||
background: #FF4D4F;
|
||||
border-radius: 16rpx;
|
||||
font-size: 20rpx;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
@@ -324,99 +470,247 @@
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.menu-divider {
|
||||
height: 2rpx;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
margin: 0 32rpx;
|
||||
}
|
||||
|
||||
/* 退出登录 */
|
||||
.logout-section {
|
||||
padding: 0 32rpx;
|
||||
margin-top: 48rpx;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
width: 100%;
|
||||
padding: 28rpx;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 16rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.logout-btn:active {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.bottom-space {
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
/* 海报弹窗 */
|
||||
.poster-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: fadeIn 0.3s;
|
||||
}
|
||||
|
||||
.poster-content {
|
||||
width: 90%;
|
||||
max-width: 600rpx;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(20rpx);
|
||||
border-radius: 32rpx;
|
||||
/* ===== 统计卡片 ===== */
|
||||
.stats-card {
|
||||
padding: 32rpx;
|
||||
animation: slideUp 0.4s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(100rpx);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.poster-header {
|
||||
.card-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #ffffff;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.poster-title {
|
||||
.stats-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.stat-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 36rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-num {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.poster-close {
|
||||
font-size: 56rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
line-height: 1;
|
||||
.stat-text {
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.poster-canvas {
|
||||
/* ===== 最近阅读 ===== */
|
||||
.recent-card {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
.recent-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.recent-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.recent-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.recent-index {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.recent-title {
|
||||
font-size: 26rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.recent-btn {
|
||||
font-size: 24rpx;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
/* ===== 空状态 ===== */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 48rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 64rpx;
|
||||
opacity: 0.5;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.empty-btn {
|
||||
margin-top: 16rpx;
|
||||
font-size: 26rpx;
|
||||
color: #00CED1;
|
||||
}
|
||||
|
||||
/* ===== 匹配记录 ===== */
|
||||
.match-card {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
/* ===== 登录弹窗 ===== */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(20rpx);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
padding: 48rpx;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 100%;
|
||||
height: 800rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
max-width: 640rpx;
|
||||
background: #1c1c1e;
|
||||
border-radius: 32rpx;
|
||||
padding: 48rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
top: 24rpx;
|
||||
right: 24rpx;
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.login-icon {
|
||||
font-size: 96rpx;
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.save-poster-btn {
|
||||
width: 100%;
|
||||
.login-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.login-desc {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-bottom: 48rpx;
|
||||
}
|
||||
|
||||
.btn-wechat {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16rpx;
|
||||
padding: 28rpx;
|
||||
background: #07C160;
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
border-radius: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-wechat::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-wechat-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.btn-phone {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16rpx;
|
||||
padding: 28rpx;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
border-radius: 24rpx;
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.btn-phone::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-phone-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.login-notice {
|
||||
display: block;
|
||||
margin-top: 32rpx;
|
||||
font-size: 22rpx;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* ===== 底部留白 ===== */
|
||||
.bottom-space {
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
45
miniprogram/pages/purchases/purchases.js
Normal file
45
miniprogram/pages/purchases/purchases.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Soul创业实验 - 订单页
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
orders: [],
|
||||
loading: true
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
|
||||
this.loadOrders()
|
||||
},
|
||||
|
||||
async loadOrders() {
|
||||
this.setData({ loading: true })
|
||||
try {
|
||||
// 模拟订单数据
|
||||
const purchasedSections = app.globalData.purchasedSections || []
|
||||
const orders = purchasedSections.map((id, index) => ({
|
||||
id: `order_${index}`,
|
||||
sectionId: id,
|
||||
title: `章节 ${id}`,
|
||||
amount: 1,
|
||||
status: 'completed',
|
||||
createTime: new Date(Date.now() - index * 86400000).toLocaleDateString()
|
||||
}))
|
||||
this.setData({ orders })
|
||||
} catch (e) {
|
||||
console.error('加载订单失败:', e)
|
||||
} finally {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
goToRead(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
wx.navigateTo({ url: `/pages/read/read?id=${id}` })
|
||||
},
|
||||
|
||||
goBack() { wx.navigateBack() }
|
||||
})
|
||||
4
miniprogram/pages/purchases/purchases.json
Normal file
4
miniprogram/pages/purchases/purchases.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
35
miniprogram/pages/purchases/purchases.wxml
Normal file
35
miniprogram/pages/purchases/purchases.wxml
Normal file
@@ -0,0 +1,35 @@
|
||||
<!--订单页-->
|
||||
<view class="page">
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-back" bindtap="goBack">←</view>
|
||||
<text class="nav-title">我的订单</text>
|
||||
<view class="nav-placeholder"></view>
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<view class="content">
|
||||
<view class="loading" wx:if="{{loading}}">
|
||||
<view class="skeleton"></view>
|
||||
<view class="skeleton"></view>
|
||||
<view class="skeleton"></view>
|
||||
</view>
|
||||
|
||||
<view class="orders-list" wx:elif="{{orders.length > 0}}">
|
||||
<view class="order-item" wx:for="{{orders}}" wx:key="id" bindtap="goToRead" data-id="{{item.sectionId}}">
|
||||
<view class="order-info">
|
||||
<text class="order-title">{{item.title}}</text>
|
||||
<text class="order-time">{{item.createTime}}</text>
|
||||
</view>
|
||||
<view class="order-right">
|
||||
<text class="order-amount">¥{{item.amount}}</text>
|
||||
<text class="order-status">已完成</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="empty" wx:else>
|
||||
<text class="empty-icon">📦</text>
|
||||
<text class="empty-text">暂无订单</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
21
miniprogram/pages/purchases/purchases.wxss
Normal file
21
miniprogram/pages/purchases/purchases.wxss
Normal file
@@ -0,0 +1,21 @@
|
||||
.page { min-height: 100vh; background: #000; }
|
||||
.nav-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(0,0,0,0.9); backdrop-filter: blur(40rpx); display: flex; align-items: center; justify-content: space-between; padding: 0 32rpx; height: 88rpx; }
|
||||
.nav-back { width: 72rpx; height: 72rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 32rpx; color: #fff; }
|
||||
.nav-title { font-size: 36rpx; font-weight: 600; color: #00CED1; }
|
||||
.nav-placeholder { width: 72rpx; }
|
||||
.content { padding: 32rpx; }
|
||||
.loading { display: flex; flex-direction: column; gap: 24rpx; }
|
||||
.skeleton { height: 120rpx; background: linear-gradient(90deg, #1c1c1e 25%, #2c2c2e 50%, #1c1c1e 75%); background-size: 200% 100%; animation: skeleton 1.5s ease-in-out infinite; border-radius: 24rpx; }
|
||||
@keyframes skeleton { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
|
||||
.orders-list { display: flex; flex-direction: column; gap: 16rpx; }
|
||||
.order-item { display: flex; align-items: center; justify-content: space-between; padding: 24rpx; background: #1c1c1e; border-radius: 24rpx; }
|
||||
.order-item:active { background: #2c2c2e; }
|
||||
.order-info { flex: 1; }
|
||||
.order-title { font-size: 28rpx; color: #fff; display: block; margin-bottom: 8rpx; }
|
||||
.order-time { font-size: 22rpx; color: rgba(255,255,255,0.4); }
|
||||
.order-right { text-align: right; }
|
||||
.order-amount { font-size: 28rpx; font-weight: 600; color: #00CED1; display: block; margin-bottom: 4rpx; }
|
||||
.order-status { font-size: 22rpx; color: rgba(255,255,255,0.4); }
|
||||
.empty { display: flex; flex-direction: column; align-items: center; padding: 96rpx; }
|
||||
.empty-icon { font-size: 96rpx; margin-bottom: 24rpx; opacity: 0.5; }
|
||||
.empty-text { font-size: 28rpx; color: rgba(255,255,255,0.4); }
|
||||
@@ -1,343 +1,487 @@
|
||||
// pages/read/read.js
|
||||
/**
|
||||
* Soul创业实验 - 阅读页
|
||||
* 开发: 卡若
|
||||
* 技术支持: 存客宝
|
||||
*/
|
||||
|
||||
const app = getApp()
|
||||
const paymentUtil = require('../../utils/payment')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
chapterId: '',
|
||||
chapterInfo: {},
|
||||
contentHtml: '',
|
||||
// 系统信息
|
||||
statusBarHeight: 44,
|
||||
navBarHeight: 88,
|
||||
|
||||
// 章节信息
|
||||
sectionId: '',
|
||||
section: null,
|
||||
partTitle: '',
|
||||
chapterTitle: '',
|
||||
|
||||
// 内容
|
||||
content: '',
|
||||
previewContent: '',
|
||||
contentParagraphs: [],
|
||||
previewParagraphs: [],
|
||||
loading: true,
|
||||
hasPrev: false,
|
||||
hasNext: false,
|
||||
isBookmarked: false,
|
||||
showCatalog: false,
|
||||
allChapters: []
|
||||
|
||||
// 用户状态
|
||||
isLoggedIn: false,
|
||||
hasFullBook: false,
|
||||
canAccess: false,
|
||||
purchasedCount: 0,
|
||||
|
||||
// 阅读进度
|
||||
readingProgress: 0,
|
||||
showPaywall: false,
|
||||
|
||||
// 上一篇/下一篇
|
||||
prevSection: null,
|
||||
nextSection: null,
|
||||
|
||||
// 价格
|
||||
sectionPrice: 1,
|
||||
fullBookPrice: 9.9,
|
||||
totalSections: 62,
|
||||
|
||||
// 弹窗
|
||||
showShareModal: false,
|
||||
showLoginModal: false,
|
||||
isPaying: false,
|
||||
|
||||
// 免费章节
|
||||
freeIds: ['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3']
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
const chapterId = options.id
|
||||
if (chapterId) {
|
||||
this.setData({ chapterId })
|
||||
this.loadChapter(chapterId)
|
||||
this.loadAllChapters()
|
||||
this.checkBookmark(chapterId)
|
||||
const { id, ref } = options
|
||||
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight,
|
||||
navBarHeight: app.globalData.navBarHeight,
|
||||
sectionId: id
|
||||
})
|
||||
|
||||
// 保存推荐码
|
||||
if (ref) {
|
||||
wx.setStorageSync('referral_code', ref)
|
||||
}
|
||||
|
||||
this.initSection(id)
|
||||
},
|
||||
|
||||
onPageScroll(e) {
|
||||
// 计算阅读进度
|
||||
const query = wx.createSelectorQuery()
|
||||
query.select('.page').boundingClientRect()
|
||||
query.exec((res) => {
|
||||
if (res[0]) {
|
||||
const scrollTop = e.scrollTop
|
||||
const pageHeight = res[0].height - this.data.statusBarHeight - 200
|
||||
const progress = pageHeight > 0 ? Math.min((scrollTop / pageHeight) * 100, 100) : 0
|
||||
this.setData({ readingProgress: progress })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 初始化章节
|
||||
async initSection(id) {
|
||||
this.setData({ loading: true })
|
||||
|
||||
try {
|
||||
// 模拟获取章节数据
|
||||
const section = this.getSectionInfo(id)
|
||||
const { isLoggedIn, hasFullBook, purchasedSections } = app.globalData
|
||||
|
||||
const isFree = this.data.freeIds.includes(id)
|
||||
const isPurchased = hasFullBook || (purchasedSections && purchasedSections.includes(id))
|
||||
const canAccess = isFree || isPurchased
|
||||
const purchasedCount = purchasedSections?.length || 0
|
||||
|
||||
this.setData({
|
||||
section,
|
||||
isLoggedIn,
|
||||
hasFullBook,
|
||||
canAccess,
|
||||
purchasedCount,
|
||||
showPaywall: !canAccess
|
||||
})
|
||||
|
||||
// 加载内容
|
||||
await this.loadContent(id)
|
||||
|
||||
// 获取上一篇/下一篇
|
||||
this.loadNavigation(id)
|
||||
|
||||
} catch (e) {
|
||||
console.error('初始化章节失败:', e)
|
||||
wx.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 加载章节内容
|
||||
loadChapter(chapterId) {
|
||||
this.setData({ loading: true })
|
||||
|
||||
wx.showLoading({ title: '加载中...', mask: true })
|
||||
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/book/chapter/${chapterId}`,
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
const chapter = res.data
|
||||
|
||||
// 检查是否需要购买
|
||||
if (chapter.needPurchase && !this.checkPurchased()) {
|
||||
this.showPurchaseModal()
|
||||
return
|
||||
}
|
||||
|
||||
this.setData({
|
||||
chapterInfo: {
|
||||
title: chapter.title,
|
||||
updateTime: chapter.updateTime,
|
||||
words: chapter.words,
|
||||
readTime: Math.ceil(chapter.words / 300)
|
||||
},
|
||||
contentHtml: this.markdownToHtml(chapter.content),
|
||||
hasPrev: !!chapter.prevChapterId,
|
||||
hasNext: !!chapter.nextChapterId,
|
||||
loading: false
|
||||
})
|
||||
|
||||
// 记录阅读进度
|
||||
this.recordReadProgress(chapterId)
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '章节加载失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
// 使用Mock数据
|
||||
this.loadMockChapter(chapterId)
|
||||
},
|
||||
complete: () => {
|
||||
wx.hideLoading()
|
||||
// 获取章节信息
|
||||
getSectionInfo(id) {
|
||||
// 特殊章节
|
||||
if (id === 'preface') {
|
||||
return { id: 'preface', title: '为什么我每天早上6点在Soul开播?', isFree: true, price: 0 }
|
||||
}
|
||||
if (id === 'epilogue') {
|
||||
return { id: 'epilogue', title: '这本书的真实目的', isFree: true, price: 0 }
|
||||
}
|
||||
if (id.startsWith('appendix')) {
|
||||
const appendixTitles = {
|
||||
'appendix-1': 'Soul派对房精选对话',
|
||||
'appendix-2': '创业者自检清单',
|
||||
'appendix-3': '本书提到的工具和资源'
|
||||
}
|
||||
})
|
||||
return { id, title: appendixTitles[id] || '附录', isFree: true, price: 0 }
|
||||
}
|
||||
|
||||
// 普通章节
|
||||
return {
|
||||
id: id,
|
||||
title: this.getSectionTitle(id),
|
||||
isFree: id === '1.1',
|
||||
price: 1
|
||||
}
|
||||
},
|
||||
|
||||
// 加载Mock章节
|
||||
loadMockChapter(chapterId) {
|
||||
const mockContent = `
|
||||
# 这是章节标题
|
||||
// 获取章节标题
|
||||
getSectionTitle(id) {
|
||||
const titles = {
|
||||
'1.1': '荷包:电动车出租的被动收入模式',
|
||||
'1.2': '老墨:资源整合高手的社交方法',
|
||||
'1.3': '笑声背后的MBTI',
|
||||
'1.4': '人性的三角结构:利益、情感、价值观',
|
||||
'1.5': '沟通差的问题:为什么你说的别人听不懂',
|
||||
'2.1': '相亲故事:你以为找的是人,实际是在找模式',
|
||||
'2.2': '找工作迷茫者:为什么简历解决不了人生',
|
||||
'2.3': '撸运费险:小钱困住大脑的真实心理',
|
||||
'2.4': '游戏上瘾的年轻人:不是游戏吸引他,是生活没吸引力',
|
||||
'2.5': '健康焦虑(我的糖尿病经历):疾病是人生的第一次清醒',
|
||||
'3.1': '3000万流水如何跑出来(退税模式解析)',
|
||||
'8.1': '流量杠杆:抖音、Soul、飞书',
|
||||
'9.14': '大健康私域:一个月150万的70后'
|
||||
}
|
||||
return titles[id] || `章节 ${id}`
|
||||
},
|
||||
|
||||
这是第一段内容,介绍了关于私域运营的基本概念...
|
||||
|
||||
## 第一小节
|
||||
|
||||
详细内容描述...
|
||||
|
||||
### 要点总结
|
||||
|
||||
1. 第一点
|
||||
2. 第二点
|
||||
3. 第三点
|
||||
|
||||
**重点强调的内容**
|
||||
|
||||
> 引用的内容或者金句
|
||||
`
|
||||
// 加载内容
|
||||
async loadContent(id) {
|
||||
try {
|
||||
// 尝试从API获取内容
|
||||
const res = await app.request(`/api/book/chapter/${id}`)
|
||||
if (res && res.content) {
|
||||
const lines = res.content.split('\n').filter(line => line.trim())
|
||||
const previewCount = Math.ceil(lines.length * 0.2)
|
||||
|
||||
this.setData({
|
||||
content: res.content,
|
||||
previewContent: lines.slice(0, previewCount).join('\n'),
|
||||
contentParagraphs: lines,
|
||||
previewParagraphs: lines.slice(0, previewCount),
|
||||
partTitle: res.partTitle || '',
|
||||
chapterTitle: res.chapterTitle || ''
|
||||
})
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('API加载失败,使用示例内容')
|
||||
}
|
||||
|
||||
// 使用示例内容
|
||||
const sampleContent = this.getSampleContent(id)
|
||||
const lines = sampleContent.split('\n').filter(line => line.trim())
|
||||
const previewCount = Math.ceil(lines.length * 0.2)
|
||||
|
||||
this.setData({
|
||||
chapterInfo: {
|
||||
title: '第一章|我是谁',
|
||||
updateTime: '2天前',
|
||||
words: 3200,
|
||||
readTime: 11
|
||||
},
|
||||
contentHtml: this.markdownToHtml(mockContent),
|
||||
hasPrev: false,
|
||||
hasNext: true,
|
||||
loading: false
|
||||
content: sampleContent,
|
||||
previewContent: lines.slice(0, previewCount).join('\n'),
|
||||
contentParagraphs: lines,
|
||||
previewParagraphs: lines.slice(0, previewCount)
|
||||
})
|
||||
},
|
||||
|
||||
// Markdown转HTML(简单实现)
|
||||
markdownToHtml(markdown) {
|
||||
if (!markdown) return ''
|
||||
// 获取示例内容
|
||||
getSampleContent(id) {
|
||||
return `这是《一场SOUL的创业实验场》的章节内容。
|
||||
|
||||
在Soul派对房里,每天早上6点到9点,我都会和几百个陌生人分享真实的商业故事。
|
||||
|
||||
这不是一本教你成功的鸡汤书,而是一本记录真实创业经历的实战手册。
|
||||
|
||||
我见过太多人在创业路上摔倒,不是因为他们不够努力,而是因为他们不懂得商业的底层逻辑。
|
||||
|
||||
商业的本质是什么?是流量、是供应链、是人脉,但更重要的是——认知。
|
||||
|
||||
当你的认知提升了,你才能看到别人看不到的机会。
|
||||
|
||||
这本书会告诉你:
|
||||
1. 如何找到真正赚钱的模式
|
||||
2. 如何避免常见的创业陷阱
|
||||
3. 如何构建自己的商业体系
|
||||
|
||||
希望这本书能帮助你少走弯路,在创业路上走得更稳、更远。
|
||||
|
||||
${id === 'preface' || id === 'epilogue' || id.startsWith('appendix') || id === '1.1'
|
||||
? '这是免费章节的完整内容。欢迎来到Soul创业实验场!'
|
||||
: '这是付费章节的预览内容。购买后可查看完整内容。'}`
|
||||
},
|
||||
|
||||
// 加载导航
|
||||
loadNavigation(id) {
|
||||
const sectionOrder = [
|
||||
'preface', '1.1', '1.2', '1.3', '1.4', '1.5',
|
||||
'2.1', '2.2', '2.3', '2.4', '2.5',
|
||||
'3.1', '3.2', '3.3', '3.4',
|
||||
'4.1', '4.2', '4.3', '4.4', '4.5',
|
||||
'5.1', '5.2', '5.3', '5.4', '5.5',
|
||||
'6.1', '6.2', '6.3', '6.4',
|
||||
'7.1', '7.2', '7.3', '7.4', '7.5',
|
||||
'8.1', '8.2', '8.3', '8.4', '8.5', '8.6',
|
||||
'9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '9.7', '9.8', '9.9', '9.10', '9.11', '9.12', '9.13', '9.14',
|
||||
'10.1', '10.2', '10.3', '10.4',
|
||||
'11.1', '11.2', '11.3', '11.4', '11.5',
|
||||
'epilogue'
|
||||
]
|
||||
|
||||
let html = markdown
|
||||
.replace(/### (.*)/g, '<h3>$1</h3>')
|
||||
.replace(/## (.*)/g, '<h2>$1</h2>')
|
||||
.replace(/# (.*)/g, '<h1>$1</h1>')
|
||||
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
||||
.replace(/> (.*)/g, '<blockquote>$1</blockquote>')
|
||||
.replace(/\n/g, '<br/>')
|
||||
const currentIndex = sectionOrder.indexOf(id)
|
||||
const prevId = currentIndex > 0 ? sectionOrder[currentIndex - 1] : null
|
||||
const nextId = currentIndex < sectionOrder.length - 1 ? sectionOrder[currentIndex + 1] : null
|
||||
|
||||
return html
|
||||
},
|
||||
|
||||
// 检查是否已购买
|
||||
checkPurchased() {
|
||||
return paymentUtil.checkPurchaseStatus()
|
||||
},
|
||||
|
||||
// 显示购买弹窗
|
||||
showPurchaseModal() {
|
||||
wx.showModal({
|
||||
title: '需要购买',
|
||||
content: '此章节需要购买完整版才能阅读',
|
||||
confirmText: '立即购买',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.purchase()
|
||||
} else {
|
||||
wx.navigateBack()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 购买
|
||||
purchase() {
|
||||
paymentUtil.purchaseFullBook(
|
||||
() => {
|
||||
wx.showToast({
|
||||
title: '购买成功',
|
||||
icon: 'success'
|
||||
})
|
||||
// 重新加载章节
|
||||
setTimeout(() => {
|
||||
this.loadChapter(this.data.chapterId)
|
||||
}, 1500)
|
||||
},
|
||||
() => {
|
||||
wx.showToast({
|
||||
title: '购买失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
// 记录阅读进度
|
||||
recordReadProgress(chapterId) {
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/user/read-progress`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
data: {
|
||||
chapterId,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 加载所有章节
|
||||
loadAllChapters() {
|
||||
wx.request({
|
||||
url: `${app.globalData.apiBase}/book/chapters`,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
this.setData({
|
||||
allChapters: res.data.chapters || []
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 检查书签
|
||||
checkBookmark(chapterId) {
|
||||
const bookmarks = wx.getStorageSync('bookmarks') || []
|
||||
const isBookmarked = bookmarks.includes(chapterId)
|
||||
this.setData({ isBookmarked })
|
||||
},
|
||||
|
||||
// 上一章
|
||||
prevChapter() {
|
||||
if (!this.data.hasPrev) return
|
||||
|
||||
// TODO: 获取上一章ID
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
},
|
||||
|
||||
// 下一章
|
||||
nextChapter() {
|
||||
if (!this.data.hasNext) return
|
||||
|
||||
// TODO: 获取下一章ID
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
this.setData({
|
||||
prevSection: prevId ? { id: prevId, title: this.getSectionTitle(prevId) } : null,
|
||||
nextSection: nextId ? { id: nextId, title: this.getSectionTitle(nextId) } : null
|
||||
})
|
||||
},
|
||||
|
||||
// 返回
|
||||
goBack() {
|
||||
wx.navigateBack()
|
||||
wx.navigateBack({
|
||||
fail: () => wx.switchTab({ url: '/pages/chapters/chapters' })
|
||||
})
|
||||
},
|
||||
|
||||
// 显示菜单
|
||||
showMenu() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['调整字体', '夜间模式', '分享好友'],
|
||||
success: (res) => {
|
||||
switch(res.tapIndex) {
|
||||
case 0:
|
||||
this.adjustFont()
|
||||
break
|
||||
case 1:
|
||||
this.toggleNightMode()
|
||||
break
|
||||
case 2:
|
||||
this.share()
|
||||
break
|
||||
}
|
||||
// 分享弹窗
|
||||
showShare() {
|
||||
this.setData({ showShareModal: true })
|
||||
},
|
||||
|
||||
closeShareModal() {
|
||||
this.setData({ showShareModal: false })
|
||||
},
|
||||
|
||||
// 复制链接
|
||||
copyLink() {
|
||||
const userInfo = app.globalData.userInfo
|
||||
const referralCode = userInfo?.referralCode || ''
|
||||
const shareUrl = `https://soul.ckb.fit/read/${this.data.sectionId}${referralCode ? '?ref=' + referralCode : ''}`
|
||||
|
||||
wx.setClipboardData({
|
||||
data: shareUrl,
|
||||
success: () => {
|
||||
wx.showToast({ title: '链接已复制', icon: 'success' })
|
||||
this.setData({ showShareModal: false })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 书签
|
||||
bookmark() {
|
||||
const chapterId = this.data.chapterId
|
||||
let bookmarks = wx.getStorageSync('bookmarks') || []
|
||||
// 分享到微信
|
||||
onShareAppMessage() {
|
||||
const { section, sectionId } = this.data
|
||||
const userInfo = app.globalData.userInfo
|
||||
const referralCode = userInfo?.referralCode || ''
|
||||
|
||||
if (this.data.isBookmarked) {
|
||||
// 移除书签
|
||||
bookmarks = bookmarks.filter(id => id !== chapterId)
|
||||
wx.showToast({
|
||||
title: '已移除书签',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
// 添加书签
|
||||
bookmarks.push(chapterId)
|
||||
wx.showToast({
|
||||
title: '已添加书签',
|
||||
icon: 'success'
|
||||
})
|
||||
return {
|
||||
title: `📚 ${section?.title || '推荐阅读'}`,
|
||||
path: `/pages/read/read?id=${sectionId}${referralCode ? '&ref=' + referralCode : ''}`
|
||||
}
|
||||
},
|
||||
|
||||
// 显示登录弹窗
|
||||
showLoginModal() {
|
||||
this.setData({ showLoginModal: true })
|
||||
},
|
||||
|
||||
closeLoginModal() {
|
||||
this.setData({ showLoginModal: false })
|
||||
},
|
||||
|
||||
// 微信登录
|
||||
async handleWechatLogin() {
|
||||
try {
|
||||
const result = await app.login()
|
||||
if (result) {
|
||||
this.setData({ showLoginModal: false })
|
||||
this.initSection(this.data.sectionId)
|
||||
wx.showToast({ title: '登录成功', icon: 'success' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '登录失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 手机号登录
|
||||
async handlePhoneLogin(e) {
|
||||
if (!e.detail.code) {
|
||||
return this.handleWechatLogin()
|
||||
}
|
||||
|
||||
wx.setStorageSync('bookmarks', bookmarks)
|
||||
this.setData({
|
||||
isBookmarked: !this.data.isBookmarked
|
||||
try {
|
||||
const result = await app.loginWithPhone(e.detail.code)
|
||||
if (result) {
|
||||
this.setData({ showLoginModal: false })
|
||||
this.initSection(this.data.sectionId)
|
||||
wx.showToast({ title: '登录成功', icon: 'success' })
|
||||
}
|
||||
} catch (e) {
|
||||
wx.showToast({ title: '登录失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
// 购买章节 - 直接调起支付
|
||||
async handlePurchaseSection() {
|
||||
if (!this.data.isLoggedIn) {
|
||||
this.setData({ showLoginModal: true })
|
||||
return
|
||||
}
|
||||
|
||||
await this.processPayment('section', this.data.sectionId, this.data.section.price)
|
||||
},
|
||||
|
||||
// 购买全书 - 直接调起支付
|
||||
async handlePurchaseFullBook() {
|
||||
if (!this.data.isLoggedIn) {
|
||||
this.setData({ showLoginModal: true })
|
||||
return
|
||||
}
|
||||
|
||||
await this.processPayment('fullbook', null, this.data.fullBookPrice)
|
||||
},
|
||||
|
||||
// 处理支付
|
||||
async processPayment(type, sectionId, amount) {
|
||||
this.setData({ isPaying: true })
|
||||
|
||||
try {
|
||||
// 创建订单
|
||||
let paymentData = null
|
||||
|
||||
try {
|
||||
const res = await app.request('/api/payment/create-order', {
|
||||
method: 'POST',
|
||||
data: { type, sectionId, amount }
|
||||
})
|
||||
|
||||
if (res.success && res.data) {
|
||||
paymentData = res.data
|
||||
}
|
||||
} catch (apiError) {
|
||||
console.log('API创建订单失败,使用模拟支付')
|
||||
}
|
||||
|
||||
// 如果API不可用,使用模拟支付
|
||||
if (!paymentData) {
|
||||
paymentData = {
|
||||
isMock: true,
|
||||
orderId: 'mock_' + Date.now()
|
||||
}
|
||||
}
|
||||
|
||||
// 调用微信支付或模拟支付
|
||||
if (paymentData.isMock) {
|
||||
// 模拟支付确认
|
||||
const confirmRes = await new Promise((resolve) => {
|
||||
wx.showModal({
|
||||
title: '确认支付',
|
||||
content: `支付 ¥${amount} 购买${type === 'section' ? '本章' : '全书'}?\n(测试环境模拟支付)`,
|
||||
success: (res) => resolve(res.confirm)
|
||||
})
|
||||
})
|
||||
|
||||
if (confirmRes) {
|
||||
// 模拟支付成功,更新本地数据
|
||||
this.mockPaymentSuccess(type, sectionId)
|
||||
wx.showToast({ title: '购买成功', icon: 'success' })
|
||||
}
|
||||
} else {
|
||||
// 真实微信支付
|
||||
await this.callWechatPay(paymentData)
|
||||
wx.showToast({ title: '购买成功', icon: 'success' })
|
||||
}
|
||||
|
||||
// 刷新页面
|
||||
this.initSection(this.data.sectionId)
|
||||
|
||||
} catch (e) {
|
||||
if (e.errMsg && e.errMsg.includes('cancel')) {
|
||||
wx.showToast({ title: '已取消支付', icon: 'none' })
|
||||
} else {
|
||||
wx.showToast({ title: '支付失败', icon: 'none' })
|
||||
}
|
||||
} finally {
|
||||
this.setData({ isPaying: false })
|
||||
}
|
||||
},
|
||||
|
||||
// 模拟支付成功
|
||||
mockPaymentSuccess(type, sectionId) {
|
||||
if (type === 'fullbook') {
|
||||
app.globalData.hasFullBook = true
|
||||
const userInfo = app.globalData.userInfo || {}
|
||||
userInfo.hasFullBook = true
|
||||
app.globalData.userInfo = userInfo
|
||||
wx.setStorageSync('userInfo', userInfo)
|
||||
} else if (sectionId) {
|
||||
const purchasedSections = app.globalData.purchasedSections || []
|
||||
if (!purchasedSections.includes(sectionId)) {
|
||||
purchasedSections.push(sectionId)
|
||||
app.globalData.purchasedSections = purchasedSections
|
||||
|
||||
const userInfo = app.globalData.userInfo || {}
|
||||
userInfo.purchasedSections = purchasedSections
|
||||
app.globalData.userInfo = userInfo
|
||||
wx.setStorageSync('userInfo', userInfo)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 调用微信支付
|
||||
callWechatPay(paymentData) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.requestPayment({
|
||||
timeStamp: paymentData.timeStamp,
|
||||
nonceStr: paymentData.nonceStr,
|
||||
package: paymentData.package,
|
||||
signType: paymentData.signType || 'MD5',
|
||||
paySign: paymentData.paySign,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 笔记
|
||||
note() {
|
||||
wx.navigateTo({
|
||||
url: `/pages/note/edit?chapterId=${this.data.chapterId}`
|
||||
})
|
||||
// 跳转到上一篇
|
||||
goToPrev() {
|
||||
if (this.data.prevSection) {
|
||||
wx.redirectTo({ url: `/pages/read/read?id=${this.data.prevSection.id}` })
|
||||
}
|
||||
},
|
||||
|
||||
// 显示目录
|
||||
showCatalog() {
|
||||
this.setData({ showCatalog: true })
|
||||
// 跳转到下一篇
|
||||
goToNext() {
|
||||
if (this.data.nextSection) {
|
||||
wx.redirectTo({ url: `/pages/read/read?id=${this.data.nextSection.id}` })
|
||||
}
|
||||
},
|
||||
|
||||
// 隐藏目录
|
||||
hideCatalog() {
|
||||
this.setData({ showCatalog: false })
|
||||
},
|
||||
|
||||
// 选择章节
|
||||
selectChapter(e) {
|
||||
const chapterId = e.currentTarget.dataset.id
|
||||
this.setData({
|
||||
chapterId,
|
||||
showCatalog: false
|
||||
})
|
||||
this.loadChapter(chapterId)
|
||||
this.checkBookmark(chapterId)
|
||||
},
|
||||
|
||||
// 分享
|
||||
share() {
|
||||
wx.showShareMenu({
|
||||
withShareTicket: true,
|
||||
menus: ['shareAppMessage', 'shareTimeline']
|
||||
})
|
||||
},
|
||||
|
||||
// 跳转到推广页面
|
||||
// 跳转到推广中心
|
||||
goToReferral() {
|
||||
wx.switchTab({
|
||||
url: '/pages/my/my?tab=referral'
|
||||
})
|
||||
wx.navigateTo({ url: '/pages/referral/referral' })
|
||||
},
|
||||
|
||||
// 阻止冒泡
|
||||
stopPropagation() {},
|
||||
|
||||
// 分享给好友
|
||||
onShareAppMessage() {
|
||||
const userInfo = app.getUserInfo()
|
||||
const inviteCode = userInfo ? userInfo.inviteCode : ''
|
||||
|
||||
return {
|
||||
title: this.data.chapterInfo.title,
|
||||
path: `/pages/read/read?id=${this.data.chapterId}&invite=${inviteCode}`,
|
||||
imageUrl: '/assets/images/share-chapter.png'
|
||||
}
|
||||
}
|
||||
stopPropagation() {}
|
||||
})
|
||||
|
||||
7
miniprogram/pages/read/read.json
Normal file
7
miniprogram/pages/read/read.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"enablePullDownRefresh": false,
|
||||
"backgroundTextStyle": "light",
|
||||
"backgroundColor": "#000000",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
@@ -1,112 +1,204 @@
|
||||
<!--pages/read/read.wxml-->
|
||||
<view class="container read-container">
|
||||
<!--Soul创业实验 - 阅读页 1:1还原Web版本-->
|
||||
<view class="page">
|
||||
<!-- 阅读进度条 -->
|
||||
<view class="progress-bar-fixed" style="top: {{statusBarHeight}}px;">
|
||||
<view class="progress-fill" style="width: {{readingProgress}}%;"></view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="read-header">
|
||||
<view class="header-left" bindtap="goBack">
|
||||
<text class="back-icon">←</text>
|
||||
</view>
|
||||
<view class="header-title">{{chapterInfo.title}}</view>
|
||||
<view class="header-right" bindtap="showMenu">
|
||||
<text class="menu-icon">⋯</text>
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-content">
|
||||
<view class="nav-back" bindtap="goBack">
|
||||
<text class="back-arrow">←</text>
|
||||
</view>
|
||||
<view class="nav-info">
|
||||
<text class="nav-part" wx:if="{{partTitle}}">{{partTitle}}</text>
|
||||
<text class="nav-chapter" wx:if="{{chapterTitle}}">{{chapterTitle}}</text>
|
||||
</view>
|
||||
<view class="nav-share" bindtap="showShare">
|
||||
<text class="share-icon">↗</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 章节内容 -->
|
||||
<scroll-view class="content-scroll" scroll-y enhanced show-scrollbar="{{false}}">
|
||||
<!-- 骨架屏 -->
|
||||
<view class="content-skeleton" wx:if="{{loading}}">
|
||||
<view class="skeleton skeleton-title"></view>
|
||||
<view class="skeleton skeleton-line"></view>
|
||||
<view class="skeleton skeleton-line"></view>
|
||||
<view class="skeleton skeleton-line short"></view>
|
||||
<view class="skeleton skeleton-line"></view>
|
||||
<view class="skeleton skeleton-line"></view>
|
||||
<!-- 导航栏占位 -->
|
||||
<view class="nav-placeholder" style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<!-- 阅读内容 -->
|
||||
<view class="read-content">
|
||||
<!-- 章节标题 -->
|
||||
<view class="chapter-header">
|
||||
<view class="chapter-meta">
|
||||
<text class="chapter-id">{{section.id}}</text>
|
||||
<text class="tag tag-free" wx:if="{{section.isFree}}">免费</text>
|
||||
</view>
|
||||
<text class="chapter-title">{{section.title}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 实际内容 -->
|
||||
<view class="content-wrapper" wx:if="{{!loading}}">
|
||||
<view class="chapter-title">{{chapterInfo.title}}</view>
|
||||
<view class="chapter-meta">
|
||||
<text class="meta-item">{{chapterInfo.updateTime}}</text>
|
||||
<text class="meta-divider">·</text>
|
||||
<text class="meta-item">{{chapterInfo.words}}字</text>
|
||||
<text class="meta-divider">·</text>
|
||||
<text class="meta-item">{{chapterInfo.readTime}}分钟</text>
|
||||
</view>
|
||||
<!-- 加载状态 -->
|
||||
<view class="loading-state" wx:if="{{loading}}">
|
||||
<view class="skeleton skeleton-1"></view>
|
||||
<view class="skeleton skeleton-2"></view>
|
||||
<view class="skeleton skeleton-3"></view>
|
||||
<view class="skeleton skeleton-4"></view>
|
||||
<view class="skeleton skeleton-5"></view>
|
||||
</view>
|
||||
|
||||
<view class="chapter-content markdown-body">
|
||||
<rich-text nodes="{{contentHtml}}"></rich-text>
|
||||
<!-- 完整内容 - 有权限 -->
|
||||
<view class="article" wx:if="{{!loading && canAccess}}">
|
||||
<view class="paragraph" wx:for="{{contentParagraphs}}" wx:key="index" wx:if="{{item}}">
|
||||
{{item}}
|
||||
</view>
|
||||
|
||||
<!-- 章节导航 -->
|
||||
<view class="chapter-nav">
|
||||
<button
|
||||
class="nav-btn prev-btn {{!hasPrev ? 'disabled' : ''}}"
|
||||
bindtap="prevChapter"
|
||||
disabled="{{!hasPrev}}"
|
||||
>
|
||||
上一章
|
||||
</button>
|
||||
<button
|
||||
class="nav-btn next-btn {{!hasNext ? 'disabled' : ''}}"
|
||||
bindtap="nextChapter"
|
||||
disabled="{{!hasNext}}"
|
||||
>
|
||||
下一章
|
||||
</button>
|
||||
</view>
|
||||
<view class="nav-buttons">
|
||||
<view
|
||||
class="nav-btn nav-prev {{!prevSection ? 'nav-disabled' : ''}}"
|
||||
bindtap="goToPrev"
|
||||
wx:if="{{prevSection}}"
|
||||
>
|
||||
<text class="btn-label">上一篇</text>
|
||||
<text class="btn-title">{{prevSection.title}}</text>
|
||||
</view>
|
||||
<view class="nav-btn-placeholder" wx:else></view>
|
||||
|
||||
<!-- 推广提示 -->
|
||||
<view class="promotion-tip card">
|
||||
<view class="tip-icon">💰</view>
|
||||
<view class="tip-content">
|
||||
<view class="tip-title">喜欢这本书?</view>
|
||||
<view class="tip-desc">分享给朋友,每笔成交您可获得90%佣金</view>
|
||||
<view
|
||||
class="nav-btn nav-next"
|
||||
bindtap="goToNext"
|
||||
wx:if="{{nextSection}}"
|
||||
>
|
||||
<text class="btn-label">下一篇</text>
|
||||
<view class="btn-row">
|
||||
<text class="btn-title">{{nextSection.title}}</text>
|
||||
<text class="btn-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="nav-btn nav-end" wx:else>
|
||||
<text class="btn-end-text">已是最后一篇 🎉</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分享提示 -->
|
||||
<view class="share-tip" bindtap="showShare">
|
||||
<view class="tip-content">
|
||||
<text class="tip-title">觉得不错?分享给好友</text>
|
||||
<text class="tip-desc">好友购买你获得90%佣金</text>
|
||||
</view>
|
||||
<view class="tip-btn">分享赚钱</view>
|
||||
</view>
|
||||
<button class="tip-btn" bindtap="goToReferral">去分享</button>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部工具栏 -->
|
||||
<view class="read-toolbar glass-effect">
|
||||
<view class="toolbar-item" bindtap="bookmark">
|
||||
<text class="toolbar-icon">{{isBookmarked ? '🔖' : '📑'}}</text>
|
||||
<text class="toolbar-label">书签</text>
|
||||
<!-- 预览内容 + 付费墙 - 无权限 -->
|
||||
<view class="article preview" wx:if="{{!loading && !canAccess}}">
|
||||
<view class="paragraph" wx:for="{{previewParagraphs}}" wx:key="index" wx:if="{{item}}">
|
||||
{{item}}
|
||||
</view>
|
||||
|
||||
<!-- 渐变遮罩 -->
|
||||
<view class="fade-mask"></view>
|
||||
|
||||
<!-- 付费墙 -->
|
||||
<view class="paywall" wx:if="{{showPaywall}}">
|
||||
<view class="paywall-icon">🔒</view>
|
||||
<text class="paywall-title">解锁完整内容</text>
|
||||
<text class="paywall-desc">
|
||||
已阅读20%,{{isLoggedIn ? '购买后继续阅读' : '登录并购买后继续阅读'}}
|
||||
</text>
|
||||
|
||||
<!-- 未登录时显示登录按钮 -->
|
||||
<view class="login-prompt" wx:if="{{!isLoggedIn}}">
|
||||
<view class="login-btn" bindtap="showLoginModal">
|
||||
<text class="login-btn-text">请先登录</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已登录显示购买选项 -->
|
||||
<view class="purchase-options" wx:else>
|
||||
<!-- 购买本章 - 直接调起支付 -->
|
||||
<view class="purchase-btn purchase-section" bindtap="handlePurchaseSection">
|
||||
<text class="btn-label">购买本章</text>
|
||||
<text class="btn-price brand-color">¥{{section.price}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 解锁全书 - 只有购买超过3章才显示 -->
|
||||
<view class="purchase-btn purchase-fullbook" bindtap="handlePurchaseFullBook" wx:if="{{purchasedCount >= 3}}">
|
||||
<view class="btn-left">
|
||||
<text class="btn-sparkle">✨</text>
|
||||
<text class="btn-label">解锁全部 {{totalSections}} 章</text>
|
||||
</view>
|
||||
<view class="btn-right">
|
||||
<text class="btn-price">¥{{fullBookPrice}}</text>
|
||||
<text class="btn-discount">省82%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="paywall-tip">分享给好友购买,你可获得90%佣金</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="toolbar-item" bindtap="note">
|
||||
<text class="toolbar-icon">📝</text>
|
||||
<text class="toolbar-label">笔记</text>
|
||||
</view>
|
||||
|
||||
<!-- 分享弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showShareModal}}" bindtap="closeShareModal">
|
||||
<view class="modal-content share-modal" catchtap="stopPropagation">
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">分享文章</text>
|
||||
<view class="modal-close" bindtap="closeShareModal">✕</view>
|
||||
</view>
|
||||
|
||||
<view class="share-link-box">
|
||||
<text class="link-label">你的专属分享链接</text>
|
||||
<text class="link-url">https://soul.ckb.fit/read/{{sectionId}}</text>
|
||||
<text class="link-tip">邀请码: 好友购买你获得90%佣金</text>
|
||||
</view>
|
||||
|
||||
<view class="share-buttons">
|
||||
<view class="share-btn" bindtap="copyLink">
|
||||
<view class="share-btn-icon icon-copy">📋</view>
|
||||
<text class="share-btn-text">复制链接</text>
|
||||
</view>
|
||||
<button class="share-btn" open-type="share">
|
||||
<view class="share-btn-icon icon-wechat">微</view>
|
||||
<text class="share-btn-text">微信好友</text>
|
||||
</button>
|
||||
<view class="share-btn" bindtap="goToReferral">
|
||||
<view class="share-btn-icon icon-poster">🖼️</view>
|
||||
<text class="share-btn-text">生成海报</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="toolbar-item" bindtap="showCatalog">
|
||||
<text class="toolbar-icon">📚</text>
|
||||
<text class="toolbar-label">目录</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showLoginModal}}" bindtap="closeLoginModal">
|
||||
<view class="modal-content login-modal" catchtap="stopPropagation">
|
||||
<view class="modal-close" bindtap="closeLoginModal">✕</view>
|
||||
<view class="login-icon">🔐</view>
|
||||
<text class="login-title">登录 Soul创业实验</text>
|
||||
<text class="login-desc">登录后可购买章节、参与匹配、赚取佣金</text>
|
||||
|
||||
<button class="btn-wechat" bindtap="handleWechatLogin">
|
||||
<text class="btn-wechat-icon">微</text>
|
||||
<text>微信快捷登录</text>
|
||||
</button>
|
||||
|
||||
<button class="btn-phone" open-type="getPhoneNumber" bindgetphonenumber="handlePhoneLogin">
|
||||
<text class="btn-phone-icon">📱</text>
|
||||
<text>手机号登录</text>
|
||||
</button>
|
||||
|
||||
<text class="login-notice">登录即表示同意《用户协议》和《隐私政策》</text>
|
||||
</view>
|
||||
<view class="toolbar-item" bindtap="share">
|
||||
<text class="toolbar-icon">📤</text>
|
||||
<text class="toolbar-label">分享</text>
|
||||
</view>
|
||||
|
||||
<!-- 支付中提示 -->
|
||||
<view class="modal-overlay" wx:if="{{isPaying}}" catchtap="">
|
||||
<view class="loading-box">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">支付处理中...</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 目录弹窗 -->
|
||||
<view class="catalog-modal" wx:if="{{showCatalog}}" bindtap="hideCatalog">
|
||||
<view class="catalog-content" catchtap="stopPropagation">
|
||||
<view class="catalog-header">
|
||||
<text class="catalog-title">目录</text>
|
||||
<text class="catalog-close" bindtap="hideCatalog">×</text>
|
||||
</view>
|
||||
<scroll-view class="catalog-list" scroll-y>
|
||||
<view
|
||||
class="catalog-item {{item.id === chapterId ? 'active' : ''}}"
|
||||
wx:for="{{allChapters}}"
|
||||
wx:key="id"
|
||||
bindtap="selectChapter"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<text class="catalog-item-title">{{item.title}}</text>
|
||||
<text class="catalog-item-icon" wx:if="{{item.id === chapterId}}">📖</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
160
miniprogram/pages/referral/referral.js
Normal file
160
miniprogram/pages/referral/referral.js
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Soul创业实验 - 分销中心页
|
||||
* 1:1还原Web版本
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
isLoggedIn: false,
|
||||
userInfo: null,
|
||||
|
||||
// 收益数据
|
||||
earnings: 0,
|
||||
pendingEarnings: 0,
|
||||
distributorShare: 90,
|
||||
|
||||
// 统计数据
|
||||
referralCount: 0,
|
||||
expiringCount: 0,
|
||||
|
||||
// 邀请码
|
||||
referralCode: '',
|
||||
|
||||
// 绑定用户
|
||||
showBindingList: true,
|
||||
activeTab: 'active',
|
||||
activeBindings: [],
|
||||
convertedBindings: [],
|
||||
expiredBindings: [],
|
||||
currentBindings: [],
|
||||
totalBindings: 0
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
|
||||
this.initData()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.initData()
|
||||
},
|
||||
|
||||
// 初始化数据
|
||||
initData() {
|
||||
const { isLoggedIn, userInfo } = app.globalData
|
||||
if (isLoggedIn && userInfo) {
|
||||
// 生成邀请码
|
||||
const referralCode = userInfo.referralCode || 'REFM' + (userInfo.id || Date.now().toString(36)).toUpperCase().slice(-6)
|
||||
|
||||
// 模拟绑定用户数据
|
||||
const activeBindings = [
|
||||
{ id: '1', nickname: '小明', bindingDate: '2025/12/25', daysRemaining: 5, status: 'active' },
|
||||
{ id: '2', nickname: '小红', bindingDate: '2026/1/9', daysRemaining: 20, status: 'active' },
|
||||
{ id: '3', nickname: '阿强', bindingDate: '2025/12/22', daysRemaining: 2, status: 'active' }
|
||||
]
|
||||
|
||||
const convertedBindings = [
|
||||
{ id: '4', nickname: '小李', bindingDate: '2025/12/10', commission: '8.91', orderAmount: '9.90', status: 'converted' }
|
||||
]
|
||||
|
||||
const expiredBindings = [
|
||||
{ id: '5', nickname: '小王', bindingDate: '2025/11/15', status: 'expired' }
|
||||
]
|
||||
|
||||
const expiringCount = activeBindings.filter(b => b.daysRemaining <= 7).length
|
||||
|
||||
this.setData({
|
||||
isLoggedIn: true,
|
||||
userInfo,
|
||||
earnings: (userInfo.earnings || 0).toFixed(2),
|
||||
pendingEarnings: (userInfo.pendingEarnings || 0).toFixed(2),
|
||||
referralCount: userInfo.referralCount || 0,
|
||||
referralCode,
|
||||
activeBindings,
|
||||
convertedBindings,
|
||||
expiredBindings,
|
||||
expiringCount,
|
||||
currentBindings: activeBindings,
|
||||
totalBindings: activeBindings.length + convertedBindings.length + expiredBindings.length
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 切换Tab
|
||||
switchTab(e) {
|
||||
const tab = e.currentTarget.dataset.tab
|
||||
let currentBindings = []
|
||||
|
||||
if (tab === 'active') {
|
||||
currentBindings = this.data.activeBindings
|
||||
} else if (tab === 'converted') {
|
||||
currentBindings = this.data.convertedBindings
|
||||
} else {
|
||||
currentBindings = this.data.expiredBindings
|
||||
}
|
||||
|
||||
this.setData({ activeTab: tab, currentBindings })
|
||||
},
|
||||
|
||||
// 切换绑定列表显示
|
||||
toggleBindingList() {
|
||||
this.setData({ showBindingList: !this.data.showBindingList })
|
||||
},
|
||||
|
||||
// 复制邀请链接
|
||||
copyLink() {
|
||||
const link = `https://soul.ckb.fit/?ref=${this.data.referralCode}`
|
||||
wx.setClipboardData({
|
||||
data: link,
|
||||
success: () => wx.showToast({ title: '链接已复制', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
// 生成海报
|
||||
generatePoster() {
|
||||
wx.showToast({ title: '海报功能开发中', icon: 'none' })
|
||||
},
|
||||
|
||||
// 提现
|
||||
handleWithdraw() {
|
||||
const earnings = parseFloat(this.data.earnings)
|
||||
if (earnings < 10) {
|
||||
wx.showToast({ title: '满10元可提现', icon: 'none' })
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: '提现功能开发中', icon: 'none' })
|
||||
},
|
||||
|
||||
// 显示通知
|
||||
showNotification() {
|
||||
wx.showToast({ title: '暂无新消息', icon: 'none' })
|
||||
},
|
||||
|
||||
// 显示设置
|
||||
showSettings() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['自动提现设置', '收益通知设置'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
wx.showToast({ title: '自动提现功能开发中', icon: 'none' })
|
||||
} else {
|
||||
wx.showToast({ title: '通知设置开发中', icon: 'none' })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 分享
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '📚 一场SOUL的创业实验场 - 来自派对房的真实商业故事',
|
||||
path: `/pages/index/index?ref=${this.data.referralCode}`
|
||||
}
|
||||
},
|
||||
|
||||
goBack() {
|
||||
wx.navigateBack()
|
||||
}
|
||||
})
|
||||
4
miniprogram/pages/referral/referral.json
Normal file
4
miniprogram/pages/referral/referral.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
194
miniprogram/pages/referral/referral.wxml
Normal file
194
miniprogram/pages/referral/referral.wxml
Normal file
@@ -0,0 +1,194 @@
|
||||
<!--分销中心 - 按照Web版本1:1还原-->
|
||||
<view class="page">
|
||||
<!-- 导航栏 -->
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-back" bindtap="goBack">
|
||||
<text class="back-icon">‹</text>
|
||||
</view>
|
||||
<text class="nav-title">分销中心</text>
|
||||
<view class="nav-right">
|
||||
<view class="nav-btn" bindtap="showNotification">🔔</view>
|
||||
<view class="nav-btn" bindtap="showSettings">⚙️</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<view class="content">
|
||||
<!-- 过期提醒横幅 -->
|
||||
<view class="expiring-banner" wx:if="{{expiringCount > 0}}">
|
||||
<view class="banner-icon">⚠️</view>
|
||||
<view class="banner-content">
|
||||
<text class="banner-title">{{expiringCount}} 位用户绑定即将过期</text>
|
||||
<text class="banner-desc">30天内未付款将解除绑定关系</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 收益卡片 -->
|
||||
<view class="earnings-card">
|
||||
<view class="earnings-bg"></view>
|
||||
<view class="earnings-main">
|
||||
<view class="earnings-header">
|
||||
<view class="earnings-left">
|
||||
<view class="wallet-icon">💰</view>
|
||||
<view class="earnings-info">
|
||||
<text class="earnings-label">累计收益</text>
|
||||
<text class="commission-rate">{{distributorShare}}% 返利</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="earnings-right">
|
||||
<text class="earnings-value">¥{{earnings}}</text>
|
||||
<text class="pending-text">待结算: ¥{{pendingEarnings}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="withdraw-btn {{earnings < 10 ? 'btn-disabled' : ''}}" bindtap="handleWithdraw">
|
||||
{{earnings < 10 ? '满10元可提现' : '申请提现'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 数据统计 -->
|
||||
<view class="stats-grid">
|
||||
<view class="stat-card">
|
||||
<text class="stat-value">{{activeBindings.length}}</text>
|
||||
<text class="stat-label">绑定中</text>
|
||||
</view>
|
||||
<view class="stat-card">
|
||||
<text class="stat-value">{{convertedBindings.length}}</text>
|
||||
<text class="stat-label">已付款</text>
|
||||
</view>
|
||||
<view class="stat-card">
|
||||
<text class="stat-value orange">{{expiringCount}}</text>
|
||||
<text class="stat-label">即将过期</text>
|
||||
</view>
|
||||
<view class="stat-card">
|
||||
<text class="stat-value">{{referralCount}}</text>
|
||||
<text class="stat-label">总邀请</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 推广规则 -->
|
||||
<view class="rules-card">
|
||||
<view class="rules-header">
|
||||
<view class="rules-icon">ℹ️</view>
|
||||
<text class="rules-title">推广规则</text>
|
||||
</view>
|
||||
<view class="rules-list">
|
||||
<text class="rule-item">• 好友通过你的链接购买,<text class="gold">立享5%优惠</text></text>
|
||||
<text class="rule-item">• 好友成功付款后,你获得 <text class="brand">{{distributorShare}}%</text> 收益</text>
|
||||
<text class="rule-item">• 绑定期<text class="brand">30天</text>,期满未付款自动解除</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 绑定用户列表 -->
|
||||
<view class="binding-card">
|
||||
<view class="binding-header" bindtap="toggleBindingList">
|
||||
<view class="binding-title">
|
||||
<text class="binding-icon">👥</text>
|
||||
<text class="title-text">绑定用户</text>
|
||||
<text class="binding-count">({{totalBindings}})</text>
|
||||
</view>
|
||||
<text class="toggle-icon">{{showBindingList ? '▲' : '▼'}}</text>
|
||||
</view>
|
||||
|
||||
<block wx:if="{{showBindingList}}">
|
||||
<!-- Tab切换 -->
|
||||
<view class="binding-tabs">
|
||||
<view
|
||||
class="tab-item {{activeTab === 'active' ? 'tab-active' : ''}}"
|
||||
bindtap="switchTab"
|
||||
data-tab="active"
|
||||
>绑定中 ({{activeBindings.length}})</view>
|
||||
<view
|
||||
class="tab-item {{activeTab === 'converted' ? 'tab-active' : ''}}"
|
||||
bindtap="switchTab"
|
||||
data-tab="converted"
|
||||
>已付款 ({{convertedBindings.length}})</view>
|
||||
<view
|
||||
class="tab-item {{activeTab === 'expired' ? 'tab-active' : ''}}"
|
||||
bindtap="switchTab"
|
||||
data-tab="expired"
|
||||
>已过期 ({{expiredBindings.length}})</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户列表 -->
|
||||
<view class="binding-list">
|
||||
<block wx:if="{{currentBindings.length === 0}}">
|
||||
<view class="empty-state">
|
||||
<text class="empty-icon">👤</text>
|
||||
<text class="empty-text">暂无用户</text>
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view
|
||||
class="binding-item"
|
||||
wx:for="{{currentBindings}}"
|
||||
wx:key="id"
|
||||
>
|
||||
<view class="user-avatar {{item.status === 'converted' ? 'avatar-converted' : item.status === 'expired' ? 'avatar-expired' : ''}}">
|
||||
<text wx:if="{{item.status === 'converted'}}">✓</text>
|
||||
<text wx:elif="{{item.status === 'expired'}}">⏰</text>
|
||||
<text wx:else>{{item.nickname[0] || '用'}}</text>
|
||||
</view>
|
||||
<view class="user-info">
|
||||
<text class="user-name">{{item.nickname || '匿名用户'}}</text>
|
||||
<text class="user-time">绑定于 {{item.bindingDate}}</text>
|
||||
</view>
|
||||
<view class="user-status">
|
||||
<block wx:if="{{item.status === 'converted'}}">
|
||||
<text class="status-amount">+¥{{item.commission}}</text>
|
||||
<text class="status-order">订单 ¥{{item.orderAmount}}</text>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<text class="status-tag {{item.daysRemaining <= 3 ? 'tag-red' : item.daysRemaining <= 7 ? 'tag-orange' : 'tag-green'}}">
|
||||
{{item.status === 'expired' ? '已过期' : item.daysRemaining + '天'}}
|
||||
</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 我的邀请码 -->
|
||||
<view class="invite-card">
|
||||
<view class="invite-header">
|
||||
<text class="invite-title">我的邀请码</text>
|
||||
<view class="invite-code-box">
|
||||
<text class="invite-code">{{referralCode}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="invite-tip">好友通过你的链接购买<text class="gold">立省5%</text>,你获得<text class="brand">{{distributorShare}}%</text>收益</text>
|
||||
</view>
|
||||
|
||||
<!-- 分享按钮 -->
|
||||
<view class="share-section">
|
||||
<view class="share-item" bindtap="generatePoster">
|
||||
<view class="share-icon poster">🖼️</view>
|
||||
<view class="share-info">
|
||||
<text class="share-title">生成推广海报</text>
|
||||
<text class="share-desc">一键生成精美海报分享</text>
|
||||
</view>
|
||||
<text class="share-arrow">→</text>
|
||||
</view>
|
||||
|
||||
<button class="share-item share-btn" open-type="share">
|
||||
<view class="share-icon wechat">💬</view>
|
||||
<view class="share-info">
|
||||
<text class="share-title">分享到朋友圈</text>
|
||||
<text class="share-desc">复制文案发朋友圈</text>
|
||||
</view>
|
||||
<text class="share-arrow">→</text>
|
||||
</button>
|
||||
|
||||
<view class="share-item" bindtap="copyLink">
|
||||
<view class="share-icon link">🔗</view>
|
||||
<view class="share-info">
|
||||
<text class="share-title">更多分享方式</text>
|
||||
<text class="share-desc">使用系统分享功能</text>
|
||||
</view>
|
||||
<text class="share-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
114
miniprogram/pages/referral/referral.wxss
Normal file
114
miniprogram/pages/referral/referral.wxss
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 分销中心页面样式 - 1:1还原Web版本 */
|
||||
.page { min-height: 100vh; background: #000; padding-bottom: 64rpx; }
|
||||
|
||||
/* 导航栏 */
|
||||
.nav-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(0,0,0,0.9); backdrop-filter: blur(40rpx); display: flex; align-items: center; justify-content: space-between; padding: 0 32rpx; height: 88rpx; }
|
||||
.nav-back { width: 64rpx; height: 64rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
|
||||
.back-icon { font-size: 40rpx; color: rgba(255,255,255,0.6); font-weight: 300; }
|
||||
.nav-title { font-size: 34rpx; font-weight: 600; color: #fff; }
|
||||
.nav-right { display: flex; gap: 16rpx; }
|
||||
.nav-btn { width: 64rpx; height: 64rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 28rpx; }
|
||||
|
||||
.content { padding: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
|
||||
/* 过期提醒横幅 */
|
||||
.expiring-banner { display: flex; align-items: center; gap: 24rpx; padding: 24rpx; background: rgba(255,165,0,0.1); border: 2rpx solid rgba(255,165,0,0.3); border-radius: 24rpx; margin-bottom: 24rpx; }
|
||||
.banner-icon { width: 80rpx; height: 80rpx; background: rgba(255,165,0,0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 40rpx; flex-shrink: 0; }
|
||||
.banner-content { flex: 1; }
|
||||
.banner-title { font-size: 28rpx; font-weight: 500; color: #fff; display: block; }
|
||||
.banner-desc { font-size: 24rpx; color: rgba(255,165,0,0.8); margin-top: 4rpx; display: block; }
|
||||
|
||||
/* 收益卡片 */
|
||||
.earnings-card { position: relative; background: linear-gradient(135deg, rgba(0,206,209,0.15) 0%, rgba(32,178,170,0.1) 50%, rgba(0,139,139,0.05) 100%); border: 2rpx solid rgba(0,206,209,0.2); border-radius: 32rpx; padding: 40rpx; margin-bottom: 24rpx; overflow: hidden; width: 100%; box-sizing: border-box; }
|
||||
.earnings-bg { position: absolute; top: -50rpx; right: -50rpx; width: 200rpx; height: 200rpx; background: rgba(0,206,209,0.1); border-radius: 50%; filter: blur(60rpx); }
|
||||
.earnings-main { position: relative; }
|
||||
.earnings-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 32rpx; }
|
||||
.earnings-left { display: flex; align-items: center; gap: 16rpx; }
|
||||
.wallet-icon { width: 80rpx; height: 80rpx; background: rgba(0,206,209,0.2); border-radius: 20rpx; display: flex; align-items: center; justify-content: center; font-size: 40rpx; }
|
||||
.earnings-info { display: flex; flex-direction: column; gap: 4rpx; }
|
||||
.earnings-label { font-size: 24rpx; color: rgba(255,255,255,0.6); }
|
||||
.commission-rate { font-size: 24rpx; color: #00CED1; font-weight: 500; }
|
||||
.earnings-right { text-align: right; }
|
||||
.earnings-value { font-size: 56rpx; font-weight: 700; color: #fff; display: block; }
|
||||
.pending-text { font-size: 22rpx; color: rgba(255,255,255,0.5); }
|
||||
|
||||
.withdraw-btn { padding: 24rpx; background: #00CED1; color: #000; font-size: 28rpx; font-weight: 600; text-align: center; border-radius: 24rpx; }
|
||||
.withdraw-btn.btn-disabled { background: rgba(0,206,209,0.3); color: rgba(0,0,0,0.5); }
|
||||
|
||||
/* 数据统计 */
|
||||
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16rpx; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.stat-card { background: #1c1c1e; border-radius: 24rpx; padding: 24rpx 16rpx; text-align: center; }
|
||||
.stat-value { font-size: 40rpx; font-weight: 700; color: #fff; display: block; }
|
||||
.stat-value.orange { color: #FFA500; }
|
||||
.stat-label { font-size: 20rpx; color: rgba(255,255,255,0.5); margin-top: 8rpx; display: block; }
|
||||
|
||||
/* 推广规则 */
|
||||
.rules-card { background: rgba(0,206,209,0.05); border: 2rpx solid rgba(0,206,209,0.2); border-radius: 24rpx; padding: 24rpx; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.rules-header { display: flex; align-items: center; gap: 16rpx; margin-bottom: 16rpx; }
|
||||
.rules-icon { width: 56rpx; height: 56rpx; background: rgba(0,206,209,0.2); border-radius: 16rpx; display: flex; align-items: center; justify-content: center; font-size: 28rpx; }
|
||||
.rules-title { font-size: 28rpx; font-weight: 500; color: #fff; }
|
||||
.rules-list { padding-left: 8rpx; }
|
||||
.rule-item { font-size: 24rpx; color: rgba(255,255,255,0.6); line-height: 1.8; display: block; }
|
||||
.rule-item .gold { color: #FFD700; }
|
||||
.rule-item .brand { color: #00CED1; }
|
||||
|
||||
/* 绑定用户卡片 */
|
||||
.binding-card { background: #1c1c1e; border-radius: 32rpx; overflow: hidden; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.binding-header { display: flex; align-items: center; justify-content: space-between; padding: 28rpx 32rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.binding-title { display: flex; align-items: center; gap: 12rpx; }
|
||||
.binding-icon { font-size: 36rpx; }
|
||||
.title-text { font-size: 30rpx; font-weight: 600; color: #fff; }
|
||||
.binding-count { font-size: 26rpx; color: rgba(255,255,255,0.5); }
|
||||
.toggle-icon { font-size: 24rpx; color: rgba(255,255,255,0.5); }
|
||||
|
||||
/* Tab切换 */
|
||||
.binding-tabs { display: flex; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.tab-item { flex: 1; padding: 24rpx 0; text-align: center; font-size: 26rpx; color: rgba(255,255,255,0.5); position: relative; }
|
||||
.tab-item.tab-active { color: #00CED1; }
|
||||
.tab-item.tab-active::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 80rpx; height: 4rpx; background: #00CED1; border-radius: 4rpx; }
|
||||
|
||||
/* 用户列表 */
|
||||
.binding-list { max-height: 640rpx; overflow-y: auto; }
|
||||
.empty-state { padding: 80rpx 0; text-align: center; }
|
||||
.empty-icon { font-size: 64rpx; display: block; margin-bottom: 16rpx; }
|
||||
.empty-text { font-size: 26rpx; color: rgba(255,255,255,0.5); }
|
||||
|
||||
.binding-item { display: flex; align-items: center; padding: 24rpx 32rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.binding-item:last-child { border-bottom: none; }
|
||||
.user-avatar { width: 80rpx; height: 80rpx; border-radius: 50%; background: rgba(0,206,209,0.2); display: flex; align-items: center; justify-content: center; font-size: 28rpx; font-weight: 600; color: #00CED1; margin-right: 24rpx; flex-shrink: 0; }
|
||||
.user-avatar.avatar-converted { background: rgba(76,175,80,0.2); color: #4CAF50; }
|
||||
.user-avatar.avatar-expired { background: rgba(158,158,158,0.2); color: #9E9E9E; }
|
||||
.user-info { flex: 1; }
|
||||
.user-name { font-size: 28rpx; color: #fff; font-weight: 500; display: block; }
|
||||
.user-time { font-size: 22rpx; color: rgba(255,255,255,0.5); margin-top: 4rpx; display: block; }
|
||||
.user-status { text-align: right; }
|
||||
.status-amount { font-size: 28rpx; color: #4CAF50; font-weight: 600; display: block; }
|
||||
.status-order { font-size: 22rpx; color: rgba(255,255,255,0.5); }
|
||||
.status-tag { font-size: 22rpx; padding: 8rpx 16rpx; border-radius: 16rpx; }
|
||||
.status-tag.tag-green { background: rgba(76,175,80,0.2); color: #4CAF50; }
|
||||
.status-tag.tag-orange { background: rgba(255,165,0,0.2); color: #FFA500; }
|
||||
.status-tag.tag-red { background: rgba(244,67,54,0.2); color: #F44336; }
|
||||
|
||||
/* 邀请码卡片 */
|
||||
.invite-card { background: #1c1c1e; border-radius: 32rpx; padding: 32rpx; margin-bottom: 24rpx; width: 100%; box-sizing: border-box; }
|
||||
.invite-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16rpx; }
|
||||
.invite-title { font-size: 28rpx; font-weight: 600; color: #fff; }
|
||||
.invite-code-box { background: rgba(0,206,209,0.15); padding: 12rpx 24rpx; border-radius: 16rpx; }
|
||||
.invite-code { font-size: 26rpx; font-weight: 600; color: #00CED1; font-family: monospace; letter-spacing: 2rpx; }
|
||||
.invite-tip { font-size: 24rpx; color: rgba(255,255,255,0.5); }
|
||||
.invite-tip .gold { color: #FFD700; }
|
||||
.invite-tip .brand { color: #00CED1; }
|
||||
|
||||
/* 分享区域 */
|
||||
.share-section { display: flex; flex-direction: column; gap: 16rpx; width: 100%; }
|
||||
.share-item { display: flex; align-items: center; background: #1c1c1e; border-radius: 24rpx; padding: 24rpx 32rpx; border: none; margin: 0; text-align: left; width: 100%; box-sizing: border-box; }
|
||||
.share-item::after { border: none; }
|
||||
.share-icon { width: 96rpx; height: 96rpx; border-radius: 20rpx; display: flex; align-items: center; justify-content: center; font-size: 48rpx; margin-right: 24rpx; flex-shrink: 0; }
|
||||
.share-icon.poster { background: rgba(103,58,183,0.2); }
|
||||
.share-icon.wechat { background: rgba(7,193,96,0.2); }
|
||||
.share-icon.link { background: rgba(158,158,158,0.2); }
|
||||
.share-info { flex: 1; }
|
||||
.share-title { font-size: 28rpx; color: #fff; font-weight: 500; display: block; }
|
||||
.share-desc { font-size: 22rpx; color: rgba(255,255,255,0.5); margin-top: 4rpx; display: block; }
|
||||
.share-arrow { font-size: 28rpx; color: rgba(255,255,255,0.3); }
|
||||
.share-btn { line-height: normal; font-size: inherit; }
|
||||
192
miniprogram/pages/settings/settings.js
Normal file
192
miniprogram/pages/settings/settings.js
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Soul创业实验 - 设置页
|
||||
* 账号绑定功能
|
||||
*/
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
isLoggedIn: false,
|
||||
userInfo: null,
|
||||
version: '1.0.0',
|
||||
|
||||
// 绑定信息
|
||||
phoneNumber: '',
|
||||
wechatId: '',
|
||||
alipayAccount: '',
|
||||
|
||||
// 绑定弹窗
|
||||
showBindModal: false,
|
||||
bindType: '', // phone | wechat | alipay
|
||||
bindValue: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.setData({
|
||||
statusBarHeight: app.globalData.statusBarHeight,
|
||||
isLoggedIn: app.globalData.isLoggedIn,
|
||||
userInfo: app.globalData.userInfo
|
||||
})
|
||||
this.loadBindingInfo()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.loadBindingInfo()
|
||||
},
|
||||
|
||||
// 加载绑定信息
|
||||
loadBindingInfo() {
|
||||
const { userInfo, isLoggedIn } = app.globalData
|
||||
if (isLoggedIn && userInfo) {
|
||||
// 从本地存储或用户信息中获取绑定数据
|
||||
const phoneNumber = wx.getStorageSync('user_phone') || userInfo.phone || ''
|
||||
const wechatId = wx.getStorageSync('user_wechat') || userInfo.wechat || ''
|
||||
const alipayAccount = wx.getStorageSync('user_alipay') || userInfo.alipay || ''
|
||||
|
||||
this.setData({
|
||||
isLoggedIn: true,
|
||||
userInfo,
|
||||
phoneNumber,
|
||||
wechatId,
|
||||
alipayAccount
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 绑定手机号
|
||||
bindPhone() {
|
||||
this.setData({
|
||||
showBindModal: true,
|
||||
bindType: 'phone',
|
||||
bindValue: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 绑定微信号
|
||||
bindWechat() {
|
||||
this.setData({
|
||||
showBindModal: true,
|
||||
bindType: 'wechat',
|
||||
bindValue: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 绑定支付宝
|
||||
bindAlipay() {
|
||||
this.setData({
|
||||
showBindModal: true,
|
||||
bindType: 'alipay',
|
||||
bindValue: ''
|
||||
})
|
||||
},
|
||||
|
||||
// 输入绑定值
|
||||
onBindInput(e) {
|
||||
let value = e.detail.value
|
||||
if (this.data.bindType === 'phone') {
|
||||
value = value.replace(/\D/g, '').slice(0, 11)
|
||||
}
|
||||
this.setData({ bindValue: value })
|
||||
},
|
||||
|
||||
// 确认绑定
|
||||
confirmBind() {
|
||||
const { bindType, bindValue } = this.data
|
||||
|
||||
if (!bindValue) {
|
||||
wx.showToast({ title: '请输入内容', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 验证
|
||||
if (bindType === 'phone' && !/^1[3-9]\d{9}$/.test(bindValue)) {
|
||||
wx.showToast({ title: '请输入正确的手机号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
if (bindType === 'wechat' && bindValue.length < 6) {
|
||||
wx.showToast({ title: '微信号至少6位', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
if (bindType === 'alipay' && !bindValue.includes('@') && !/^1[3-9]\d{9}$/.test(bindValue)) {
|
||||
wx.showToast({ title: '请输入正确的支付宝账号', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 保存绑定信息
|
||||
if (bindType === 'phone') {
|
||||
wx.setStorageSync('user_phone', bindValue)
|
||||
this.setData({ phoneNumber: bindValue })
|
||||
} else if (bindType === 'wechat') {
|
||||
wx.setStorageSync('user_wechat', bindValue)
|
||||
this.setData({ wechatId: bindValue })
|
||||
} else if (bindType === 'alipay') {
|
||||
wx.setStorageSync('user_alipay', bindValue)
|
||||
this.setData({ alipayAccount: bindValue })
|
||||
}
|
||||
|
||||
this.setData({ showBindModal: false })
|
||||
wx.showToast({ title: '绑定成功', icon: 'success' })
|
||||
},
|
||||
|
||||
// 关闭绑定弹窗
|
||||
closeBindModal() {
|
||||
this.setData({ showBindModal: false })
|
||||
},
|
||||
|
||||
// 清除缓存
|
||||
clearCache() {
|
||||
wx.showModal({
|
||||
title: '清除缓存',
|
||||
content: '确定要清除本地缓存吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 保留登录信息,只清除其他缓存
|
||||
const token = wx.getStorageSync('token')
|
||||
const userInfo = wx.getStorageSync('userInfo')
|
||||
wx.clearStorageSync()
|
||||
if (token) wx.setStorageSync('token', token)
|
||||
if (userInfo) wx.setStorageSync('userInfo', userInfo)
|
||||
wx.showToast({ title: '缓存已清除', icon: 'success' })
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
handleLogout() {
|
||||
wx.showModal({
|
||||
title: '退出登录',
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
app.logout()
|
||||
this.setData({
|
||||
isLoggedIn: false,
|
||||
userInfo: null,
|
||||
phoneNumber: '',
|
||||
wechatId: '',
|
||||
alipayAccount: ''
|
||||
})
|
||||
wx.showToast({ title: '已退出登录', icon: 'success' })
|
||||
setTimeout(() => wx.navigateBack(), 1500)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 联系客服
|
||||
contactService() {
|
||||
wx.setClipboardData({
|
||||
data: '28533368',
|
||||
success: () => wx.showToast({ title: '客服微信已复制', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
// 阻止冒泡
|
||||
stopPropagation() {},
|
||||
|
||||
goBack() { wx.navigateBack() }
|
||||
})
|
||||
4
miniprogram/pages/settings/settings.json
Normal file
4
miniprogram/pages/settings/settings.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
138
miniprogram/pages/settings/settings.wxml
Normal file
138
miniprogram/pages/settings/settings.wxml
Normal file
@@ -0,0 +1,138 @@
|
||||
<!--设置页 - 账号绑定功能-->
|
||||
<view class="page">
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-back" bindtap="goBack">
|
||||
<text class="back-icon">‹</text>
|
||||
</view>
|
||||
<text class="nav-title">设置</text>
|
||||
<view class="nav-placeholder"></view>
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<view class="content">
|
||||
<!-- 账号绑定 -->
|
||||
<view class="bind-card" wx:if="{{isLoggedIn}}">
|
||||
<view class="card-header">
|
||||
<text class="card-icon">🛡️</text>
|
||||
<view class="card-title-wrap">
|
||||
<text class="card-title">账号绑定</text>
|
||||
<text class="card-desc">绑定后可用于提现和找伙伴功能</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bind-list">
|
||||
<!-- 手机号 -->
|
||||
<view class="bind-item">
|
||||
<view class="bind-left">
|
||||
<view class="bind-icon phone-icon">📱</view>
|
||||
<view class="bind-info">
|
||||
<text class="bind-label">手机号</text>
|
||||
<text class="bind-value">{{phoneNumber || '未绑定'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bind-right">
|
||||
<text class="bind-check" wx:if="{{phoneNumber}}">✓</text>
|
||||
<text class="bind-btn" wx:else bindtap="bindPhone">去绑定</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 微信号 -->
|
||||
<view class="bind-item">
|
||||
<view class="bind-left">
|
||||
<view class="bind-icon wechat-icon">💬</view>
|
||||
<view class="bind-info">
|
||||
<text class="bind-label">微信号</text>
|
||||
<text class="bind-value">{{wechatId || '未绑定'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bind-right">
|
||||
<text class="bind-check" wx:if="{{wechatId}}">✓</text>
|
||||
<text class="bind-btn" wx:else bindtap="bindWechat">去绑定</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付宝 -->
|
||||
<view class="bind-item">
|
||||
<view class="bind-left">
|
||||
<view class="bind-icon alipay-icon">💳</view>
|
||||
<view class="bind-info">
|
||||
<text class="bind-label">支付宝</text>
|
||||
<text class="bind-value">{{alipayAccount || '未绑定'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bind-right">
|
||||
<text class="bind-check" wx:if="{{alipayAccount}}">✓</text>
|
||||
<text class="bind-btn" wx:else bindtap="bindAlipay">去绑定</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提现提示 -->
|
||||
<view class="tip-banner" wx:if="{{isLoggedIn && !wechatId && !alipayAccount}}">
|
||||
<text class="tip-text">提示:绑定至少一个支付方式(微信或支付宝)才能使用提现功能</text>
|
||||
</view>
|
||||
|
||||
<!-- 其他设置 -->
|
||||
<view class="settings-group">
|
||||
<view class="settings-item" bindtap="contactService">
|
||||
<view class="item-left">
|
||||
<text class="item-icon">💬</text>
|
||||
<text class="item-title">联系客服</text>
|
||||
</view>
|
||||
<text class="item-arrow">→</text>
|
||||
</view>
|
||||
<view class="settings-item" bindtap="clearCache">
|
||||
<view class="item-left">
|
||||
<text class="item-icon">🗑️</text>
|
||||
<text class="item-title">清除缓存</text>
|
||||
</view>
|
||||
<text class="item-arrow">→</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="settings-group">
|
||||
<view class="settings-item">
|
||||
<view class="item-left">
|
||||
<text class="item-icon">ℹ️</text>
|
||||
<text class="item-title">当前版本</text>
|
||||
</view>
|
||||
<text class="item-value">v{{version}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="logout-btn" wx:if="{{isLoggedIn}}" bindtap="handleLogout">退出登录</view>
|
||||
</view>
|
||||
|
||||
<!-- 绑定弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showBindModal}}" bindtap="closeBindModal">
|
||||
<view class="modal-content" catchtap="stopPropagation">
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">绑定{{bindType === 'phone' ? '手机号' : bindType === 'wechat' ? '微信号' : '支付宝'}}</text>
|
||||
<view class="modal-close" bindtap="closeBindModal">✕</view>
|
||||
</view>
|
||||
|
||||
<view class="modal-body">
|
||||
<view class="input-wrapper">
|
||||
<input
|
||||
type="{{bindType === 'phone' ? 'number' : 'text'}}"
|
||||
class="form-input"
|
||||
placeholder="{{bindType === 'phone' ? '请输入11位手机号' : bindType === 'wechat' ? '请输入微信号' : '请输入支付宝账号'}}"
|
||||
placeholder-class="input-placeholder"
|
||||
value="{{bindValue}}"
|
||||
bindinput="onBindInput"
|
||||
maxlength="{{bindType === 'phone' ? 11 : 50}}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<text class="bind-tip">
|
||||
{{bindType === 'phone' ? '绑定手机号后可用于找伙伴匹配' : bindType === 'wechat' ? '绑定微信号后可用于找伙伴匹配和好友添加' : '绑定支付宝后可用于提现收益'}}
|
||||
</text>
|
||||
|
||||
<view class="btn-primary {{!bindValue ? 'btn-disabled' : ''}}" bindtap="confirmBind">
|
||||
确认绑定
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
64
miniprogram/pages/settings/settings.wxss
Normal file
64
miniprogram/pages/settings/settings.wxss
Normal file
@@ -0,0 +1,64 @@
|
||||
/* 设置页样式 */
|
||||
.page { min-height: 100vh; background: #000; padding-bottom: 64rpx; }
|
||||
|
||||
/* 导航栏 */
|
||||
.nav-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(0,0,0,0.9); backdrop-filter: blur(40rpx); display: flex; align-items: center; justify-content: space-between; padding: 0 32rpx; height: 88rpx; }
|
||||
.nav-back { width: 64rpx; height: 64rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
|
||||
.back-icon { font-size: 40rpx; color: rgba(255,255,255,0.6); font-weight: 300; }
|
||||
.nav-title { font-size: 34rpx; font-weight: 600; color: #fff; }
|
||||
.nav-placeholder { width: 64rpx; }
|
||||
|
||||
.content { padding: 24rpx; }
|
||||
|
||||
/* 账号绑定卡片 */
|
||||
.bind-card { background: #1c1c1e; border-radius: 32rpx; padding: 32rpx; margin-bottom: 24rpx; border: 2rpx solid rgba(0,206,209,0.2); }
|
||||
.card-header { display: flex; align-items: flex-start; gap: 16rpx; margin-bottom: 24rpx; padding-bottom: 24rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.card-icon { font-size: 40rpx; }
|
||||
.card-title-wrap { flex: 1; }
|
||||
.card-title { font-size: 30rpx; font-weight: 600; color: #fff; display: block; }
|
||||
.card-desc { font-size: 24rpx; color: rgba(255,255,255,0.5); margin-top: 4rpx; display: block; }
|
||||
|
||||
.bind-list { display: flex; flex-direction: column; gap: 24rpx; }
|
||||
.bind-item { display: flex; align-items: center; justify-content: space-between; padding: 16rpx 0; }
|
||||
.bind-left { display: flex; align-items: center; gap: 20rpx; }
|
||||
.bind-icon { width: 72rpx; height: 72rpx; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 32rpx; }
|
||||
.bind-icon.phone-icon { background: rgba(0,206,209,0.2); }
|
||||
.bind-icon.wechat-icon { background: rgba(158,158,158,0.2); }
|
||||
.bind-icon.alipay-icon { background: rgba(158,158,158,0.2); }
|
||||
.bind-info { display: flex; flex-direction: column; gap: 4rpx; }
|
||||
.bind-label { font-size: 28rpx; color: #fff; font-weight: 500; }
|
||||
.bind-value { font-size: 24rpx; color: rgba(255,255,255,0.5); }
|
||||
.bind-right { display: flex; align-items: center; }
|
||||
.bind-check { color: #00CED1; font-size: 32rpx; }
|
||||
.bind-btn { color: #00CED1; font-size: 26rpx; }
|
||||
|
||||
/* 提现提示 */
|
||||
.tip-banner { background: rgba(255,165,0,0.1); border: 2rpx solid rgba(255,165,0,0.3); border-radius: 20rpx; padding: 20rpx 24rpx; margin-bottom: 24rpx; }
|
||||
.tip-text { font-size: 24rpx; color: #FFA500; line-height: 1.5; }
|
||||
|
||||
/* 设置组 */
|
||||
.settings-group { background: #1c1c1e; border-radius: 32rpx; overflow: hidden; margin-bottom: 24rpx; }
|
||||
.settings-item { display: flex; align-items: center; justify-content: space-between; padding: 28rpx 32rpx; border-bottom: 2rpx solid rgba(255,255,255,0.05); }
|
||||
.settings-item:last-child { border-bottom: none; }
|
||||
.item-left { display: flex; align-items: center; gap: 16rpx; }
|
||||
.item-icon { font-size: 36rpx; }
|
||||
.item-title { font-size: 28rpx; color: #fff; }
|
||||
.item-arrow { font-size: 28rpx; color: rgba(255,255,255,0.3); }
|
||||
.item-value { font-size: 26rpx; color: rgba(255,255,255,0.5); }
|
||||
|
||||
/* 退出登录按钮 */
|
||||
.logout-btn { margin-top: 48rpx; padding: 28rpx; background: rgba(244,67,54,0.1); border: 2rpx solid rgba(244,67,54,0.3); border-radius: 24rpx; text-align: center; font-size: 28rpx; color: #F44336; }
|
||||
|
||||
/* 弹窗 */
|
||||
.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; z-index: 1000; }
|
||||
.modal-content { width: 600rpx; background: #1c1c1e; border-radius: 32rpx; overflow: hidden; }
|
||||
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 32rpx; border-bottom: 2rpx solid rgba(255,255,255,0.1); }
|
||||
.modal-title { font-size: 32rpx; font-weight: 600; color: #fff; }
|
||||
.modal-close { width: 56rpx; height: 56rpx; background: rgba(255,255,255,0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 28rpx; color: rgba(255,255,255,0.6); }
|
||||
.modal-body { padding: 32rpx; }
|
||||
.input-wrapper { margin-bottom: 24rpx; }
|
||||
.form-input { width: 100%; padding: 24rpx; background: rgba(0,0,0,0.3); border: 2rpx solid rgba(255,255,255,0.1); border-radius: 20rpx; font-size: 28rpx; color: #fff; box-sizing: border-box; }
|
||||
.input-placeholder { color: rgba(255,255,255,0.3); }
|
||||
.bind-tip { font-size: 24rpx; color: rgba(255,255,255,0.5); margin-bottom: 32rpx; display: block; }
|
||||
.btn-primary { padding: 24rpx; background: #00CED1; color: #000; font-size: 28rpx; font-weight: 600; text-align: center; border-radius: 24rpx; }
|
||||
.btn-primary.btn-disabled { background: rgba(0,206,209,0.3); color: rgba(0,0,0,0.5); }
|
||||
Reference in New Issue
Block a user