diff --git a/miniprogram/pages/read/read.js b/miniprogram/pages/read/read.js
index 91fb696..ac7eb28 100644
--- a/miniprogram/pages/read/read.js
+++ b/miniprogram/pages/read/read.js
@@ -47,7 +47,9 @@ Page({
// 弹窗
showShareModal: false,
showLoginModal: false,
+ showPosterModal: false,
isPaying: false,
+ isGeneratingPoster: false,
// 免费章节
freeIds: ['preface', 'epilogue', '1.1', 'appendix-1', 'appendix-2', 'appendix-3']
@@ -530,6 +532,160 @@ Page({
wx.navigateTo({ url: '/pages/referral/referral' })
},
+ // 生成海报
+ async generatePoster() {
+ wx.showLoading({ title: '生成中...' })
+ this.setData({ showPosterModal: true, isGeneratingPoster: true })
+
+ try {
+ const ctx = wx.createCanvasContext('posterCanvas', this)
+ const { section, contentParagraphs } = this.data
+ const userInfo = app.globalData.userInfo
+ const referralCode = userInfo?.referralCode || 'SOUL'
+
+ // 海报尺寸 300x450
+ const width = 300
+ const height = 450
+
+ // 背景渐变
+ const grd = ctx.createLinearGradient(0, 0, 0, height)
+ grd.addColorStop(0, '#1a1a2e')
+ grd.addColorStop(1, '#16213e')
+ ctx.setFillStyle(grd)
+ ctx.fillRect(0, 0, width, height)
+
+ // 顶部装饰条
+ ctx.setFillStyle('#00CED1')
+ ctx.fillRect(0, 0, width, 4)
+
+ // 标题区域
+ ctx.setFillStyle('#ffffff')
+ ctx.setFontSize(14)
+ ctx.fillText('📚 Soul创业派对', 20, 35)
+
+ // 章节标题
+ ctx.setFontSize(18)
+ ctx.setFillStyle('#ffffff')
+ const title = section?.title || '精彩内容'
+ const titleLines = this.wrapText(ctx, title, width - 40, 18)
+ let y = 70
+ titleLines.forEach(line => {
+ ctx.fillText(line, 20, y)
+ y += 26
+ })
+
+ // 分隔线
+ ctx.setStrokeStyle('rgba(255,255,255,0.1)')
+ ctx.beginPath()
+ ctx.moveTo(20, y + 10)
+ ctx.lineTo(width - 20, y + 10)
+ ctx.stroke()
+
+ // 内容摘要
+ ctx.setFontSize(12)
+ ctx.setFillStyle('rgba(255,255,255,0.8)')
+ y += 30
+ const summary = contentParagraphs.slice(0, 3).join(' ').slice(0, 150) + '...'
+ const summaryLines = this.wrapText(ctx, summary, width - 40, 12)
+ summaryLines.slice(0, 6).forEach(line => {
+ ctx.fillText(line, 20, y)
+ y += 20
+ })
+
+ // 底部区域背景
+ ctx.setFillStyle('rgba(0,206,209,0.1)')
+ ctx.fillRect(0, height - 120, width, 120)
+
+ // 小程序码占位(实际需要获取小程序码图片)
+ ctx.setFillStyle('#ffffff')
+ ctx.beginPath()
+ ctx.arc(width - 55, height - 60, 35, 0, Math.PI * 2)
+ ctx.fill()
+ ctx.setFillStyle('#00CED1')
+ ctx.setFontSize(10)
+ ctx.fillText('扫码阅读', width - 72, height - 58)
+
+ // 邀请信息
+ ctx.setFillStyle('#ffffff')
+ ctx.setFontSize(12)
+ ctx.fillText('长按识别 · 阅读全文', 20, height - 70)
+ ctx.setFillStyle('#FFD700')
+ ctx.setFontSize(11)
+ ctx.fillText(`邀请码: ${referralCode}`, 20, height - 50)
+ ctx.setFillStyle('rgba(255,255,255,0.6)')
+ ctx.setFontSize(10)
+ ctx.fillText('好友购买你获90%收益', 20, height - 32)
+
+ ctx.draw(true, () => {
+ wx.hideLoading()
+ this.setData({ isGeneratingPoster: false })
+ })
+ } catch (e) {
+ console.error('生成海报失败:', e)
+ wx.hideLoading()
+ wx.showToast({ title: '生成失败', icon: 'none' })
+ this.setData({ showPosterModal: false, isGeneratingPoster: false })
+ }
+ },
+
+ // 文字换行处理
+ wrapText(ctx, text, maxWidth, fontSize) {
+ const lines = []
+ let line = ''
+ for (let i = 0; i < text.length; i++) {
+ const testLine = line + text[i]
+ const metrics = ctx.measureText(testLine)
+ if (metrics.width > maxWidth && line) {
+ lines.push(line)
+ line = text[i]
+ } else {
+ line = testLine
+ }
+ }
+ if (line) lines.push(line)
+ return lines
+ },
+
+ // 关闭海报弹窗
+ closePosterModal() {
+ this.setData({ showPosterModal: false })
+ },
+
+ // 保存海报到相册
+ savePoster() {
+ wx.canvasToTempFilePath({
+ canvasId: 'posterCanvas',
+ success: (res) => {
+ wx.saveImageToPhotosAlbum({
+ filePath: res.tempFilePath,
+ success: () => {
+ wx.showToast({ title: '已保存到相册', icon: 'success' })
+ this.setData({ showPosterModal: false })
+ },
+ fail: (err) => {
+ if (err.errMsg.includes('auth deny')) {
+ wx.showModal({
+ title: '提示',
+ content: '需要相册权限才能保存海报',
+ confirmText: '去设置',
+ success: (res) => {
+ if (res.confirm) {
+ wx.openSetting()
+ }
+ }
+ })
+ } else {
+ wx.showToast({ title: '保存失败', icon: 'none' })
+ }
+ }
+ })
+ },
+ fail: () => {
+ wx.showToast({ title: '生成图片失败', icon: 'none' })
+ }
+ }, this)
+ },
+
// 阻止冒泡
stopPropagation() {}
})
diff --git a/miniprogram/pages/read/read.wxml b/miniprogram/pages/read/read.wxml
index 4c74f6f..3ee142e 100644
--- a/miniprogram/pages/read/read.wxml
+++ b/miniprogram/pages/read/read.wxml
@@ -80,13 +80,37 @@
-
-
-
- 推荐好友,共同成长
- 邀请好友加入,享90%推广收益
+
+
+
+
+
+
+ 🖼️
+ 生成海报
+
+
+
+
+
+
+
+
+ 💰
+
+ 推荐好友,共同成长
+ 邀请好友购买,享90%推广收益
+
+
+
+ →
+
- 立即推广
@@ -171,34 +195,27 @@
-
-
-
+
+
+
-
- 你的专属分享链接
- https://soul.quwanzhi.com/read/{{sectionId}}
- 邀请码: 好友购买你获得90%佣金
+
+
+
-
-
- 📋
- 复制链接
-
-
-
- 🖼️
- 生成海报
+
+
+ 💾
+ 保存到相册
+
+ 长按海报可直接分享到微信
diff --git a/miniprogram/pages/read/read.wxss b/miniprogram/pages/read/read.wxss
index 639f77e..a2d6a30 100644
--- a/miniprogram/pages/read/read.wxss
+++ b/miniprogram/pages/read/read.wxss
@@ -396,42 +396,123 @@
color: rgba(255, 255, 255, 0.6);
}
-/* ===== 分享提示 ===== */
-.share-tip {
+/* ===== 分享操作区 ===== */
+.action-section {
+ margin-top: 64rpx;
+ padding: 32rpx;
+ background: rgba(255, 255, 255, 0.03);
+ border-radius: 24rpx;
+ border: 2rpx solid rgba(255, 255, 255, 0.05);
+}
+
+.action-header {
+ margin-bottom: 24rpx;
+}
+
+.action-title {
+ font-size: 28rpx;
+ color: rgba(255, 255, 255, 0.6);
+}
+
+.action-buttons {
+ display: flex;
+ gap: 24rpx;
+}
+
+.action-btn {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12rpx;
+ padding: 28rpx 24rpx;
+ border-radius: 20rpx;
+ border: none;
+ background: transparent;
+ line-height: normal;
+}
+
+.action-btn::after {
+ border: none;
+}
+
+.btn-share {
+ background: rgba(7, 193, 96, 0.15);
+ border: 2rpx solid rgba(7, 193, 96, 0.3);
+}
+
+.btn-poster {
+ background: rgba(255, 215, 0, 0.15);
+ border: 2rpx solid rgba(255, 215, 0, 0.3);
+}
+
+.action-icon {
+ font-size: 36rpx;
+}
+
+.action-text {
+ font-size: 28rpx;
+ color: #ffffff;
+ font-weight: 500;
+}
+
+/* ===== 推广提示区 ===== */
+.promo-section {
+ margin-top: 32rpx;
+}
+
+.promo-card {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx;
- background: linear-gradient(90deg, rgba(255, 215, 0, 0.1) 0%, transparent 100%);
+ background: linear-gradient(135deg, rgba(255, 215, 0, 0.1) 0%, rgba(255, 165, 0, 0.05) 100%);
border: 2rpx solid rgba(255, 215, 0, 0.2);
border-radius: 24rpx;
}
-.tip-content {
+.promo-left {
+ display: flex;
+ align-items: center;
+ gap: 20rpx;
+}
+
+.promo-icon {
+ width: 80rpx;
+ height: 80rpx;
+ background: rgba(255, 215, 0, 0.2);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 36rpx;
+}
+
+.promo-info {
flex: 1;
}
-.tip-title {
- font-size: 28rpx;
+.promo-title {
+ font-size: 30rpx;
color: #ffffff;
- font-weight: 500;
+ font-weight: 600;
display: block;
}
-.tip-desc {
+.promo-desc {
font-size: 24rpx;
- color: rgba(255, 255, 255, 0.6);
+ color: rgba(255, 255, 255, 0.5);
display: block;
margin-top: 8rpx;
}
-.tip-btn {
- padding: 16rpx 32rpx;
- background: #FFD700;
- color: #000000;
- font-size: 28rpx;
- font-weight: 500;
- border-radius: 16rpx;
+.promo-right {
+ padding-left: 20rpx;
+}
+
+.promo-arrow {
+ font-size: 32rpx;
+ color: #FFD700;
}
/* ===== 弹窗 ===== */
@@ -792,3 +873,56 @@
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
}
+
+/* ===== 海报弹窗 ===== */
+.poster-modal {
+ padding-bottom: calc(64rpx + env(safe-area-inset-bottom));
+}
+
+.poster-preview {
+ display: flex;
+ justify-content: center;
+ margin: 32rpx 0;
+ padding: 24rpx;
+ background: rgba(0, 0, 0, 0.3);
+ border-radius: 24rpx;
+}
+
+.poster-canvas {
+ border-radius: 16rpx;
+ box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.5);
+}
+
+.poster-actions {
+ display: flex;
+ gap: 24rpx;
+ margin-bottom: 24rpx;
+}
+
+.poster-btn {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12rpx;
+ padding: 28rpx;
+ border-radius: 24rpx;
+ font-size: 30rpx;
+ font-weight: 500;
+}
+
+.btn-save {
+ background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%);
+ color: #ffffff;
+}
+
+.btn-icon {
+ font-size: 32rpx;
+}
+
+.poster-tip {
+ font-size: 24rpx;
+ color: rgba(255, 255, 255, 0.4);
+ text-align: center;
+ display: block;
+}
diff --git a/miniprogram/pages/referral/referral.js b/miniprogram/pages/referral/referral.js
index dfd58b5..a16d3e9 100644
--- a/miniprogram/pages/referral/referral.js
+++ b/miniprogram/pages/referral/referral.js
@@ -29,7 +29,11 @@ Page({
convertedBindings: [],
expiredBindings: [],
currentBindings: [],
- totalBindings: 0
+ totalBindings: 0,
+
+ // 海报
+ showPosterModal: false,
+ isGeneratingPoster: false
},
onLoad() {
@@ -133,10 +137,152 @@ Page({
})
},
- // 生成海报
- generatePoster() {
- wx.showToast({ title: '海报功能开发中', icon: 'none' })
+ // 生成推广海报
+ async generatePoster() {
+ wx.showLoading({ title: '生成中...' })
+ this.setData({ showPosterModal: true, isGeneratingPoster: true })
+
+ try {
+ const ctx = wx.createCanvasContext('promoPosterCanvas', this)
+ const { referralCode, userInfo, earnings, referralCount, distributorShare } = this.data
+
+ // 海报尺寸 300x450
+ const width = 300
+ const height = 450
+
+ // 背景渐变
+ const grd = ctx.createLinearGradient(0, 0, 0, height)
+ grd.addColorStop(0, '#0f0c29')
+ grd.addColorStop(0.5, '#302b63')
+ grd.addColorStop(1, '#24243e')
+ ctx.setFillStyle(grd)
+ ctx.fillRect(0, 0, width, height)
+
+ // 顶部装饰
+ ctx.setFillStyle('#FFD700')
+ ctx.fillRect(0, 0, width, 5)
+
+ // 标题
+ ctx.setFillStyle('#FFD700')
+ ctx.setFontSize(20)
+ ctx.fillText('📚 Soul创业派对', 20, 45)
+
+ // 副标题
+ ctx.setFillStyle('rgba(255,255,255,0.8)')
+ ctx.setFontSize(12)
+ ctx.fillText('来自派对房的真实商业故事', 20, 70)
+
+ // 书籍介绍区域
+ ctx.setFillStyle('rgba(255,255,255,0.05)')
+ ctx.fillRect(15, 90, width - 30, 100)
+
+ ctx.setFillStyle('#ffffff')
+ ctx.setFontSize(14)
+ ctx.fillText('✨ 62个真实商业案例', 25, 115)
+ ctx.fillText('💡 私域运营实战经验', 25, 140)
+ ctx.fillText('🎯 从0到1创业方法论', 25, 165)
+
+ // 推广者信息
+ ctx.setFillStyle('#00CED1')
+ ctx.setFontSize(13)
+ ctx.fillText(`推荐人: ${userInfo?.nickname || '创业者'}`, 20, 220)
+
+ // 统计数据
+ ctx.setFillStyle('rgba(255,255,255,0.6)')
+ ctx.setFontSize(11)
+ ctx.fillText(`已推荐 ${referralCount} 人 · 累计收益 ¥${parseFloat(earnings || 0).toFixed(0)}`, 20, 245)
+
+ // 优惠信息
+ ctx.setFillStyle('rgba(255,215,0,0.15)')
+ ctx.fillRect(15, 265, width - 30, 50)
+ ctx.setFillStyle('#FFD700')
+ ctx.setFontSize(14)
+ ctx.fillText('🎁 专属福利', 25, 290)
+ ctx.setFillStyle('#ffffff')
+ ctx.setFontSize(12)
+ ctx.fillText('通过此码购买立享5%优惠', 25, 308)
+
+ // 底部区域
+ ctx.setFillStyle('rgba(0,206,209,0.1)')
+ ctx.fillRect(0, height - 110, width, 110)
+
+ // 邀请码
+ ctx.setFillStyle('#ffffff')
+ ctx.setFontSize(12)
+ ctx.fillText('我的邀请码', 20, height - 85)
+ ctx.setFillStyle('#00CED1')
+ ctx.setFontSize(22)
+ ctx.fillText(referralCode, 20, height - 55)
+
+ // 小程序码占位
+ ctx.setFillStyle('#ffffff')
+ ctx.beginPath()
+ ctx.arc(width - 55, height - 55, 40, 0, Math.PI * 2)
+ ctx.fill()
+ ctx.setFillStyle('#00CED1')
+ ctx.setFontSize(9)
+ ctx.fillText('扫码', width - 62, height - 55)
+ ctx.fillText('购买', width - 62, height - 42)
+
+ // 底部提示
+ ctx.setFillStyle('rgba(255,255,255,0.5)')
+ ctx.setFontSize(10)
+ ctx.fillText(`推广返利 ${distributorShare}%`, 20, height - 20)
+
+ ctx.draw(true, () => {
+ wx.hideLoading()
+ this.setData({ isGeneratingPoster: false })
+ })
+ } catch (e) {
+ console.error('生成海报失败:', e)
+ wx.hideLoading()
+ wx.showToast({ title: '生成失败', icon: 'none' })
+ this.setData({ showPosterModal: false, isGeneratingPoster: false })
+ }
},
+
+ // 关闭海报弹窗
+ closePosterModal() {
+ this.setData({ showPosterModal: false })
+ },
+
+ // 保存海报
+ savePoster() {
+ wx.canvasToTempFilePath({
+ canvasId: 'promoPosterCanvas',
+ success: (res) => {
+ wx.saveImageToPhotosAlbum({
+ filePath: res.tempFilePath,
+ success: () => {
+ wx.showToast({ title: '已保存到相册', icon: 'success' })
+ this.setData({ showPosterModal: false })
+ },
+ fail: (err) => {
+ if (err.errMsg.includes('auth deny')) {
+ wx.showModal({
+ title: '提示',
+ content: '需要相册权限才能保存海报',
+ confirmText: '去设置',
+ success: (res) => {
+ if (res.confirm) {
+ wx.openSetting()
+ }
+ }
+ })
+ } else {
+ wx.showToast({ title: '保存失败', icon: 'none' })
+ }
+ }
+ })
+ },
+ fail: () => {
+ wx.showToast({ title: '生成图片失败', icon: 'none' })
+ }
+ }, this)
+ },
+
+ // 阻止冒泡
+ stopPropagation() {},
// 分享到朋友圈
shareToMoments() {
diff --git a/miniprogram/pages/referral/referral.wxml b/miniprogram/pages/referral/referral.wxml
index 2df1d7e..b55d7ca 100644
--- a/miniprogram/pages/referral/referral.wxml
+++ b/miniprogram/pages/referral/referral.wxml
@@ -172,23 +172,47 @@
→
-
+
+
-
- 🔗
+
+ 📝
- 更多分享方式
- 使用系统分享功能
+ 复制朋友圈文案
+ 一键复制推广文案
→
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 💾
+ 保存到相册
+
+
+
+ 保存后可分享到朋友圈或发送给好友
+
+
diff --git a/miniprogram/pages/referral/referral.wxss b/miniprogram/pages/referral/referral.wxss
index e14be1f..ba9df6e 100644
--- a/miniprogram/pages/referral/referral.wxss
+++ b/miniprogram/pages/referral/referral.wxss
@@ -111,4 +111,22 @@
.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; }
+.share-btn-wechat { line-height: normal; font-size: inherit; }
+
+/* 弹窗 */
+.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.7); backdrop-filter: blur(20rpx); display: flex; align-items: flex-end; justify-content: center; z-index: 1000; }
+.modal-content { width: 100%; max-width: 750rpx; background: #1c1c1e; border-radius: 48rpx 48rpx 0 0; padding: 48rpx; padding-bottom: calc(48rpx + env(safe-area-inset-bottom)); animation: slideUp 0.3s ease; }
+@keyframes slideUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
+.modal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 32rpx; }
+.modal-title { font-size: 36rpx; font-weight: 600; color: #fff; }
+.modal-close { 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); }
+
+/* 海报弹窗 */
+.poster-modal { padding-bottom: calc(64rpx + env(safe-area-inset-bottom)); }
+.poster-preview { display: flex; justify-content: center; margin: 32rpx 0; padding: 24rpx; background: rgba(0,0,0,0.3); border-radius: 24rpx; }
+.poster-canvas { border-radius: 16rpx; box-shadow: 0 16rpx 48rpx rgba(0,0,0,0.5); }
+.poster-actions { display: flex; gap: 24rpx; margin-bottom: 24rpx; }
+.poster-btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 12rpx; padding: 28rpx; border-radius: 24rpx; font-size: 30rpx; font-weight: 500; color: #fff; }
+.btn-save { background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%); }
+.btn-icon { font-size: 32rpx; }
+.poster-tip { font-size: 24rpx; color: rgba(255,255,255,0.4); text-align: center; display: block; }