/** * Soul创业派对 - 分销中心页 * * 可见数据: * - 绑定用户数(当前有效绑定) * - 通过链接进的人数(总访问量) * - 带来的付款人数(已转化购买) * - 收益统计(90%归分发者) */ const app = getApp() Page({ data: { statusBarHeight: 44, isLoggedIn: false, userInfo: null, // === 核心可见数据 === bindingCount: 0, // 绑定用户数(当前有效) visitCount: 0, // 通过链接进的人数 paidCount: 0, // 带来的付款人数 unboughtCount: 0, // 待购买人数(绑定但未付款) expiredCount: 0, // 已过期人数 // === 收益数据 === earnings: 0, // 已结算收益 pendingEarnings: 0, // 待结算收益 withdrawnEarnings: 0, // 已提现金额 shareRate: 90, // 分成比例(90%) // === 统计数据 === referralCount: 0, // 总推荐人数 expiringCount: 0, // 即将过期人数 // 邀请码 referralCode: '', // 绑定用户列表 showBindingList: true, activeTab: 'active', activeBindings: [], convertedBindings: [], expiredBindings: [], currentBindings: [], totalBindings: 0, // 收益明细 earningsDetails: [], // 海报 showPosterModal: false, isGeneratingPoster: false }, onLoad() { this.setData({ statusBarHeight: app.globalData.statusBarHeight }) this.initData() }, onShow() { this.initData() }, // 初始化数据 async initData() { const { isLoggedIn, userInfo } = app.globalData if (isLoggedIn && userInfo) { // 生成邀请码 const referralCode = userInfo.referralCode || 'SOUL' + (userInfo.id || Date.now().toString(36)).toUpperCase().slice(-6) // 尝试从API获取真实数据 let realData = null try { const res = await app.request('/api/referral/data', { method: 'GET', data: { userId: userInfo.id } }) if (res.success) { realData = res.data console.log('[Referral] 获取推广数据成功:', realData) } } catch (e) { console.log('[Referral] 获取推广数据失败,使用本地数据') } // 使用真实数据或默认值 let activeBindings = realData?.activeUsers || [] let convertedBindings = realData?.convertedUsers || [] let expiredBindings = realData?.expiredUsers || [] // 兼容旧字段名 if (!activeBindings.length && realData?.activeBindings) { activeBindings = realData.activeBindings } if (!convertedBindings.length && realData?.convertedBindings) { convertedBindings = realData.convertedBindings } if (!expiredBindings.length && realData?.expiredBindings) { expiredBindings = realData.expiredBindings } const expiringCount = activeBindings.filter(b => b.daysRemaining <= 7 && b.daysRemaining > 0).length // 计算各类统计 const bindingCount = realData?.bindingCount || activeBindings.length const paidCount = realData?.paidCount || convertedBindings.length const expiredCount = realData?.expiredCount || expiredBindings.length const unboughtCount = bindingCount // 绑定中但未付款的 // 格式化用户数据 const formatUser = (user, type) => ({ id: user.id, nickname: user.nickname || '用户' + (user.id || '').slice(-4), avatar: user.avatar, status: type, daysRemaining: user.daysRemaining || 0, bindingDate: user.bindingDate ? this.formatDate(user.bindingDate) : '--', commission: user.commission || 0, orderAmount: user.orderAmount || 0 }) this.setData({ isLoggedIn: true, userInfo, // 核心可见数据 bindingCount, visitCount: realData?.visitCount || 0, paidCount, unboughtCount, expiredCount, // 收益数据 earnings: realData?.earnings || 0, pendingEarnings: realData?.pendingEarnings || 0, withdrawnEarnings: realData?.withdrawnEarnings || 0, shareRate: realData?.shareRate || 90, // 统计 referralCount: realData?.referralCount || realData?.stats?.totalBindings || activeBindings.length + convertedBindings.length, expiringCount, referralCode, activeBindings: activeBindings.map(u => formatUser(u, 'active')), convertedBindings: convertedBindings.map(u => formatUser(u, 'converted')), expiredBindings: expiredBindings.map(u => formatUser(u, 'expired')), currentBindings: activeBindings.map(u => formatUser(u, 'active')), totalBindings: activeBindings.length + convertedBindings.length + expiredBindings.length, // 收益明细 earningsDetails: realData?.earningsDetails || [] }) } }, // 切换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.quwanzhi.com/?ref=${this.data.referralCode}` wx.setClipboardData({ data: link, success: () => wx.showToast({ title: '链接已复制', icon: 'success' }) }) }, // 生成推广海报 async generatePoster() { wx.showLoading({ title: '生成中...', mask: true }) this.setData({ showPosterModal: true, isGeneratingPoster: true }) try { const ctx = wx.createCanvasContext('promoPosterCanvas', this) const { userInfo, earnings, referralCount, distributorShare } = this.data const userId = userInfo?.id || '' // 获取小程序码(带推荐人参数) let qrcodeImage = null try { // scene格式:ref=用户ID前20位 const scene = userId ? `ref=${userId.slice(0,20)}` : 'ref=soul' console.log('[Poster] 请求小程序码, scene:', scene) const qrRes = await app.request('/api/miniprogram/qrcode', { method: 'POST', data: { scene, page: 'pages/index/index', width: 280 } }) console.log('[Poster] 小程序码响应:', qrRes?.success, qrRes?.image?.length) if (qrRes && qrRes.success && qrRes.image) { qrcodeImage = qrRes.image console.log('[Poster] 小程序码获取成功') } else { console.log('[Poster] 响应无效:', qrRes) } } catch (e) { console.error('[Poster] 获取小程序码失败:', e) } // 海报尺寸 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} 位好友阅读`, 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 - 80, width, 80) // 底部提示 ctx.setFillStyle('#ffffff') ctx.setFontSize(13) ctx.fillText('长按识别 立即购买', 20, height - 50) ctx.setFillStyle('rgba(255,255,255,0.6)') ctx.setFontSize(11) ctx.fillText('扫码立即阅读', 20, height - 28) // 绘制小程序码 const drawQRCode = () => { return new Promise((resolve) => { if (qrcodeImage) { const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/qrcode_promo_${Date.now()}.png` const base64Data = qrcodeImage.replace(/^data:image\/\w+;base64,/, '') fs.writeFile({ filePath, data: base64Data, encoding: 'base64', success: () => { ctx.drawImage(filePath, width - 75, height - 70, 60, 60) resolve() }, fail: () => { this.drawQRPlaceholder(ctx, width, height) resolve() } }) } else { this.drawQRPlaceholder(ctx, width, height) resolve() } }) } await drawQRCode() 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 }) } }, // 绘制小程序码占位符 drawQRPlaceholder(ctx, width, height) { ctx.setFillStyle('#ffffff') ctx.beginPath() ctx.arc(width - 45, height - 40, 30, 0, Math.PI * 2) ctx.fill() ctx.setFillStyle('#00CED1') ctx.setFontSize(9) ctx.fillText('扫码', width - 52, height - 42) ctx.fillText('购买', width - 52, height - 30) }, // 关闭海报弹窗 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() { // 10条随机文案,基于书的内容 const shareTexts = [ `🔥 在派对房里听到的真实故事,比虚构的小说精彩100倍!\n\n电动车出租月入5万、私域一年赚1000万、一个人的公司月入10万...\n\n62个真实案例,搜"Soul创业派对"小程序看全部!\n\n#创业 #私域 #商业`, `💡 今天终于明白:会赚钱的人,都在用"流量杠杆"\n\n抖音、Soul、飞书...同一套内容,撬动不同平台的流量。\n\n《Soul创业派对》里的实战方法,受用终身!\n\n#流量 #副业 #创业派对`, `📚 一个70后大健康私域,一个月150万流水是怎么做到的?\n\n答案在《Soul创业派对》第9章,全是干货。\n\n搜小程序"Soul创业派对",我在里面等你\n\n#大健康 #私域运营 #真实案例`, `🎯 "分钱不是分你的钱,是分不属于对方的钱"\n\n这句话改变了我对商业合作的认知。\n\n推荐《Soul创业派对》,创业者必读!\n\n#云阿米巴 #商业思维 #创业`, `✨ 资源整合高手的社交方法论,在派对房里学到了\n\n"先让对方赚到钱,自己才能长久赚钱"\n\n这本《Soul创业派对》,每章都是实战经验\n\n#资源整合 #社交 #创业故事`, `🚀 AI工具推广:一个隐藏的高利润赛道\n\n客单价高、复购率高、需求旺盛...\n\n《Soul创业派对》里的商业机会,你发现了吗?\n\n#AI #副业 #商业机会`, `💰 美业整合:一个人的公司如何月入十万?\n\n不开店、不囤货、轻资产运营...\n\n《Soul创业派对》告诉你答案!\n\n#美业 #轻创业 #月入十万`, `🌟 3000万流水是怎么跑出来的?\n\n不是靠运气,是靠系统。\n\n《Soul创业派对》里的电商底层逻辑,值得反复看\n\n#电商 #创业 #商业系统`, `📖 "人与人之间的关系,归根结底就三个东西:利益、情感、价值观"\n\n在派对房里聊出的金句,都在《Soul创业派对》里\n\n#人性 #商业 #创业派对`, `🔔 未来职业的三个方向:技术型、资源型、服务型\n\n你属于哪一种?\n\n《Soul创业派对》帮你找到答案!\n\n#职业规划 #创业 #未来` ] // 随机选择一条文案 const randomIndex = Math.floor(Math.random() * shareTexts.length) const shareText = shareTexts[randomIndex] wx.setClipboardData({ data: shareText, success: () => { wx.showModal({ title: '文案已复制', content: '请打开微信朋友圈,粘贴分享文案,配合推广海报一起发布效果更佳!\n\n再次点击可获取新的随机文案', showCancel: false, confirmText: '去发朋友圈' }) } }) }, // 提现 - 直接到微信零钱(无门槛) async handleWithdraw() { const pendingEarnings = parseFloat(this.data.pendingEarnings) || 0 if (pendingEarnings <= 0) { wx.showToast({ title: '暂无可提现收益', icon: 'none' }) return } // 确认提现 wx.showModal({ title: '确认提现', content: `将提现 ¥${pendingEarnings.toFixed(2)} 到您的微信零钱`, confirmText: '立即提现', success: async (res) => { if (res.confirm) { await this.doWithdraw(pendingEarnings) } } }) }, // 执行提现 async doWithdraw(amount) { wx.showLoading({ title: '提现中...' }) try { const userId = app.globalData.userInfo?.id if (!userId) { wx.hideLoading() wx.showToast({ title: '请先登录', icon: 'none' }) return } const res = await app.request('/api/withdraw', { method: 'POST', data: { userId, amount } }) wx.hideLoading() if (res.success) { wx.showModal({ title: '提现成功 🎉', content: `¥${amount.toFixed(2)} 已到账您的微信零钱`, showCancel: false, confirmText: '好的' }) // 刷新数据 this.initData() } else { if (res.needBind) { wx.showModal({ title: '需要绑定微信', content: '请先在设置中绑定微信账号后再提现', confirmText: '去绑定', success: (modalRes) => { if (modalRes.confirm) { wx.navigateTo({ url: '/pages/settings/settings' }) } } }) } else { wx.showToast({ title: res.error || '提现失败', icon: 'none' }) } } } catch (e) { wx.hideLoading() console.error('[Referral] 提现失败:', e) 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}`, imageUrl: '/assets/share-cover.png' } }, // 分享到朋友圈 onShareTimeline() { return { title: `Soul创业派对 - 62个真实商业案例`, query: `ref=${this.data.referralCode}` } }, goBack() { wx.navigateBack() }, // 格式化日期 formatDate(dateStr) { if (!dateStr) return '--' const d = new Date(dateStr) const month = (d.getMonth() + 1).toString().padStart(2, '0') const day = d.getDate().toString().padStart(2, '0') return `${month}-${day}` } })