/** * Soul创业派对 - 分销中心页 * * 可见数据: * - 绑定用户数(当前有效绑定) * - 通过链接进的人数(总访问量) * - 带来的付款人数(已转化购买) * - 收益统计(90%归分发者) */ const app = getApp() Page({ data: { statusBarHeight: 44, isLoggedIn: false, userInfo: null, // === 核心可见数据 === bindingCount: 0, // 绑定用户数(当前有效) visitCount: 0, // 通过链接进的人数 paidCount: 0, // 带来的付款人数 unboughtCount: 0, // 待购买人数(绑定但未付款) expiredCount: 0, // 已过期人数 // === 收益数据 === totalCommission: 0, // 累计佣金总额(所有获得的佣金) availableEarnings: 0, // 可提现金额(未申请提现的佣金)- 字符串格式用于显示 availableEarningsNum: 0, // 可提现金额 - 数字格式用于判断 pendingWithdrawAmount: 0, // 待审核金额(已申请提现但未审核) withdrawnEarnings: 0, // 已提现金额 earnings: 0, // 已结算收益(保留兼容) pendingEarnings: 0, // 待结算收益(保留兼容) shareRate: 90, // 分成比例(90%) minWithdrawAmount: 10, // 最低提现金额(从后端获取) hasWechatId: false, // 是否已绑定微信号(未绑定时需引导去设置) // === 统计数据 === referralCount: 0, // 总推荐人数 expiringCount: 0, // 即将过期人数 // 邀请码 referralCode: '', // 绑定用户列表 showBindingList: true, activeTab: 'active', activeBindings: [], convertedBindings: [], expiredBindings: [], currentBindings: [], totalBindings: 0, // 收益明细 earningsDetails: [], // 海报 showPosterModal: false, isGeneratingPoster: false, posterQrSrc: '', posterReferralLink: '', posterNickname: '', posterNicknameInitial: '', posterCaseCount: 62, }, onLoad() { this.setData({ statusBarHeight: app.globalData.statusBarHeight }) this.initData() }, onShow() { // 从设置页返回时同步微信号绑定状态,便于提现按钮立即更新 const hasWechatId = !!(app.globalData.userInfo?.wechat || app.globalData.userInfo?.wechatId || wx.getStorageSync('user_wechat')) this.setData({ hasWechatId }) this.initData() }, // 初始化数据 async initData() { const { isLoggedIn, userInfo } = app.globalData if (isLoggedIn && userInfo) { // 显示加载提示 wx.showLoading({ title: '加载中...', mask: true // 防止触摸穿透 }) // 生成邀请码 const referralCode = userInfo.referralCode || 'SOUL' + (userInfo.id || Date.now().toString(36)).toUpperCase().slice(-6) console.log('[Referral] 开始加载分销数据,userId:', userInfo.id) // 从API获取真实数据 let realData = null try { // app.request 第一个参数是 URL 字符串(会自动拼接 baseUrl) const res = await app.request('/api/miniprogram/referral/data?userId=' + userInfo.id) console.log('[Referral] API返回:', JSON.stringify(res).substring(0, 200)) if (res && res.success && res.data) { realData = res.data console.log('[Referral] ✅ 获取推广数据成功') console.log('[Referral] - bindingCount:', realData.bindingCount) console.log('[Referral] - paidCount:', realData.paidCount) console.log('[Referral] - earnings:', realData.earnings) console.log('[Referral] - expiringCount:', realData.stats?.expiringCount) } else { console.log('[Referral] ❌ API返回格式错误:', res?.error || 'unknown') } } catch (e) { console.log('[Referral] ❌ API调用失败:', e.message || e) console.log('[Referral] 错误详情:', e) } // 使用真实数据或默认值 let activeBindings = realData?.activeUsers || [] let convertedBindings = realData?.convertedUsers || [] let expiredBindings = realData?.expiredUsers || [] console.log('[Referral] activeBindings:', activeBindings.length) console.log('[Referral] convertedBindings:', convertedBindings.length) console.log('[Referral] expiredBindings:', expiredBindings.length) // 计算即将过期的数量(7天内) const expiringCount = realData?.stats?.expiringCount || activeBindings.filter(b => b.daysRemaining <= 7 && b.daysRemaining > 0).length console.log('[Referral] expiringCount:', expiringCount) // 计算各类统计 const bindingCount = realData?.bindingCount || activeBindings.length const paidCount = realData?.paidCount || convertedBindings.length const expiredCount = realData?.expiredCount || expiredBindings.length const unboughtCount = bindingCount - paidCount // 绑定中但未付款的 // 格式化用户数据 const formatUser = (user, type) => { const formatted = { 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) : '--', expiryDate: user.expiryDate ? this.formatDate(user.expiryDate) : '--', commission: (user.commission || 0).toFixed(2), orderAmount: (user.orderAmount || 0).toFixed(2), purchaseCount: user.purchaseCount || 0, conversionDate: user.conversionDate ? this.formatDate(user.conversionDate) : '--' } console.log('[Referral] 格式化用户:', formatted.nickname, formatted.status, formatted.daysRemaining + '天') return formatted } // 格式化金额(保留两位小数) const formatMoney = (num) => { return typeof num === 'number' ? num.toFixed(2) : '0.00' } // ✅ 可提现金额 = 累计佣金 - 已提现金额 - 待审核金额,且不低于 0(防止数据不同步时出现负数) const totalCommissionNum = realData?.totalCommission || 0 const withdrawnNum = realData?.withdrawnEarnings || 0 const pendingWithdrawNum = realData?.pendingWithdrawAmount || 0 const availableEarningsNum = Math.max(0, totalCommissionNum - withdrawnNum - pendingWithdrawNum) const minWithdrawAmount = realData?.minWithdrawAmount || 10 console.log('=== [Referral] 收益计算(完整版)===') console.log('累计佣金 (totalCommission):', totalCommissionNum) console.log('已提现金额 (withdrawnEarnings):', withdrawnNum) console.log('待审核金额 (pendingWithdrawAmount):', pendingWithdrawNum) console.log('可提现金额 = 累计 - 已提现 - 待审核 =', totalCommissionNum, '-', withdrawnNum, '-', pendingWithdrawNum, '=', availableEarningsNum) console.log('最低提现金额 (minWithdrawAmount):', minWithdrawAmount) console.log('按钮判断:', availableEarningsNum, '>=', minWithdrawAmount, '=', availableEarningsNum >= minWithdrawAmount) console.log('✅ 按钮应该:', availableEarningsNum >= minWithdrawAmount ? '🟢 启用(绿色)' : '⚫ 禁用(灰色)') const hasWechatId = !!(userInfo?.wechat || userInfo?.wechatId || wx.getStorageSync('user_wechat')) this.setData({ isLoggedIn: true, userInfo, hasWechatId, // 核心可见数据 bindingCount, visitCount: realData?.visitCount || 0, paidCount, unboughtCount: expiringCount, // "即将过期"显示的是 expiringCount expiredCount, // 收益数据 - 格式化为两位小数 totalCommission: formatMoney(totalCommissionNum), availableEarnings: formatMoney(availableEarningsNum), // ✅ 使用计算后的可提现金额 availableEarningsNum: availableEarningsNum, // ✅ 数字格式用于按钮判断 pendingWithdrawAmount: formatMoney(pendingWithdrawNum), withdrawnEarnings: formatMoney(realData?.withdrawnEarnings || 0), earnings: formatMoney(realData?.earnings || 0), pendingEarnings: formatMoney(realData?.pendingEarnings || 0), shareRate: realData?.shareRate || 90, minWithdrawAmount: minWithdrawAmount, // 统计 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 || []).map(item => { // 解析商品描述,获取书名和章节 const productInfo = this.parseProductDescription(item.description, item.productType) return { id: item.id, productType: item.productType, bookTitle: productInfo.bookTitle, chapterTitle: productInfo.chapterTitle, commission: (item.commission || 0).toFixed(2), payTime: item.payTime ? this.formatDate(item.payTime) : '--', buyerNickname: item.buyerNickname || '用户', buyerAvatar: item.buyerAvatar } }) }) console.log('[Referral] ✅ 数据设置完成') console.log('[Referral] - 绑定中:', this.data.bindingCount) console.log('[Referral] - 即将过期:', this.data.expiringCount) console.log('[Referral] - 收益:', this.data.earnings) console.log('=== [Referral] 按钮状态验证 ===') console.log('累计佣金 (totalCommission):', this.data.totalCommission) console.log('待审核金额 (pendingWithdrawAmount):', this.data.pendingWithdrawAmount) console.log('可提现金额 (availableEarnings 显示):', this.data.availableEarnings) console.log('可提现金额 (availableEarningsNum 判断):', this.data.availableEarningsNum, typeof this.data.availableEarningsNum) console.log('最低提现金额 (minWithdrawAmount):', this.data.minWithdrawAmount, typeof this.data.minWithdrawAmount) console.log('按钮启用条件:', this.data.availableEarningsNum, '>=', this.data.minWithdrawAmount, '=', this.data.availableEarningsNum >= this.data.minWithdrawAmount) console.log('✅ 最终结果: 按钮应该', this.data.availableEarningsNum >= this.data.minWithdrawAmount ? '🟢 启用' : '⚫ 禁用') // 隐藏加载提示 wx.hideLoading() } else { // 未登录时也隐藏loading this.setData({ isLoading: false }) } }, // 切换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' }) }) }, // 分享到朋友圈 - 1:1 迁移 Next.js 的 handleShareToWechat shareToWechat() { const { referralCode } = this.data const referralLink = `https://soul.quwanzhi.com/?ref=${referralCode}` // 与 Next.js 完全相同的文案 const shareText = `📖 推荐一本好书《一场SOUL的创业实验场》 这是卡若每天早上6-9点在Soul派对房分享的真实商业故事,55个真实案例,讲透创业的底层逻辑。 👉 点击阅读: ${referralLink} #创业 #商业思维 #Soul派对` wx.setClipboardData({ data: shareText, success: () => { wx.showModal({ title: '朋友圈文案已复制!', content: '打开微信 → 发朋友圈 → 粘贴即可', showCancel: false, confirmText: '知道了' }) } }) }, // 更多分享方式 - 1:1 迁移 Next.js 的 handleShare handleMoreShare() { const { referralCode } = this.data const referralLink = `https://soul.quwanzhi.com/?ref=${referralCode}` // 与 Next.js 完全相同的文案 const shareText = `我正在读《一场SOUL的创业实验场》,每天6-9点的真实商业故事,推荐给你!${referralLink}` wx.setClipboardData({ data: shareText, success: () => { wx.showToast({ title: '分享文案已复制', icon: 'success', duration: 2000 }) } }) }, // 生成推广海报 - 1:1 对齐 Next.js 设计 async generatePoster() { wx.showLoading({ title: '生成中...', mask: true }) this.setData({ showPosterModal: true, isGeneratingPoster: true }) try { const { referralCode, userInfo } = this.data const nickname = userInfo?.nickname || '用户' const scene = `ref=${referralCode}` console.log('[Poster] 请求小程序码, scene:', scene) // 调用后端接口生成「小程序码」(官方 getwxacodeunlimit),不再使用 H5 二维码 const res = await app.request('/api/miniprogram/qrcode', { method: 'POST', data: { scene, // ref=XXXX page: 'pages/index/index', width: 280, }, }) if (!res || !res.success || !res.image) { console.error('[Poster] 生成小程序码失败:', res) throw new Error(res?.error || '生成小程序码失败') } // 后端返回的是 data:image/png;base64,... 需要先写入本地临时文件,再作为 的 src const base64Data = String(res.image).replace(/^data:image\/\w+;base64,/, '') const fs = wx.getFileSystemManager() const filePath = `${wx.env.USER_DATA_PATH}/poster_qrcode_${Date.now()}.png` await new Promise((resolve, reject) => { fs.writeFile({ filePath, data: base64Data, encoding: 'base64', success: () => resolve(true), fail: (err) => { console.error('[Poster] 小程序码写入本地失败:', err) reject(err) }, }) }) console.log('[Poster] 小程序码已保存到本地:', filePath) this.setData({ posterQrSrc: filePath, posterReferralLink: '', // 小程序版本不再使用 H5 链接 posterNickname: nickname, posterNicknameInitial: (nickname || '用').charAt(0), isGeneratingPoster: false }) wx.hideLoading() } catch (e) { console.error('[Poster] 生成二维码失败:', e) wx.hideLoading() wx.showToast({ title: '生成失败', icon: 'none' }) this.setData({ showPosterModal: false, isGeneratingPoster: false, posterQrSrc: '', posterReferralLink: '' }) } }, // 绘制数据卡片 drawDataCard(ctx, x, y, width, height, value, label, color) { // 卡片背景 ctx.setFillStyle('rgba(255,255,255,0.05)') this.drawRoundRect(ctx, x, y, width, height, 8) ctx.setStrokeStyle('rgba(255,255,255,0.1)') ctx.setLineWidth(1) ctx.stroke() // 数值 ctx.setFillStyle(color) ctx.setFontSize(24) ctx.setTextAlign('center') ctx.fillText(value, x + width / 2, y + 24) // 标签 ctx.setFillStyle('rgba(255,255,255,0.5)') ctx.setFontSize(10) ctx.fillText(label, x + width / 2, y + 40) }, // 绘制圆角矩形 drawRoundRect(ctx, x, y, width, height, radius) { ctx.beginPath() ctx.moveTo(x + radius, y) ctx.lineTo(x + width - radius, y) ctx.arc(x + width - radius, y + radius, radius, -Math.PI / 2, 0) ctx.lineTo(x + width, y + height - radius) ctx.arc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2) ctx.lineTo(x + radius, y + height) ctx.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI) ctx.lineTo(x, y + radius) ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5) ctx.closePath() ctx.fill() }, // 光晕(替代 createRadialGradient):用同心圆叠加模拟模糊 // centerX/centerY: 圆心坐标;radius: 最大半径;rgb: [r,g,b];maxAlpha: 最内层透明度 drawGlow(ctx, centerX, centerY, radius, rgb, maxAlpha = 0.10) { const steps = 14 for (let i = steps; i >= 1; i--) { const r = (radius * i) / steps const alpha = (maxAlpha * i) / steps ctx.setFillStyle(`rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha})`) ctx.beginPath() ctx.arc(centerX, centerY, r, 0, Math.PI * 2) ctx.fill() } }, // 绘制二维码(支持Base64和URL两种格式) async drawQRCode(ctx, qrcodeImage, x, y, size) { return new Promise((resolve) => { if (!qrcodeImage) { console.log('[Poster] 无二维码数据,绘制占位符') this.drawQRPlaceholder(ctx, x, y, size) resolve() return } // 判断是Base64还是URL if (qrcodeImage.startsWith('data:image') || !qrcodeImage.startsWith('http')) { // Base64格式(小程序码) console.log('[Poster] 绘制Base64二维码') 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: () => { console.log('[Poster] ✅ Base64写入成功') ctx.drawImage(filePath, x, y, size, size) resolve() }, fail: (err) => { console.error('[Poster] ❌ Base64写入失败:', err) this.drawQRPlaceholder(ctx, x, y, size) resolve() } }) } else { // URL格式(第三方二维码) console.log('[Poster] 下载在线二维码:', qrcodeImage) wx.downloadFile({ url: qrcodeImage, success: (res) => { if (res.statusCode === 200) { console.log('[Poster] ✅ 二维码下载成功') ctx.drawImage(res.tempFilePath, x, y, size, size) resolve() } else { console.error('[Poster] ❌ 二维码下载失败, status:', res.statusCode) this.drawQRPlaceholder(ctx, x, y, size) resolve() } }, fail: (err) => { console.error('[Poster] ❌ 二维码下载失败:', err) this.drawQRPlaceholder(ctx, x, y, size) resolve() } }) } }) }, // 绘制小程序码占位符 drawQRPlaceholder(ctx, x, y, size) { // 绘制占位符方框 ctx.setFillStyle('rgba(200,200,200,0.3)') this.drawRoundRect(ctx, x, y, size, size, 8) ctx.setFillStyle('#00CED1') ctx.setFontSize(11) ctx.setTextAlign('center') ctx.fillText('小程序码', x + size / 2, y + size / 2) }, // 关闭海报弹窗 closePosterModal() { this.setData({ showPosterModal: false }) }, // 保存海报 savePoster() { const { posterQrSrc } = this.data if (!posterQrSrc) { wx.showToast({ title: '二维码未生成', icon: 'none' }) return } wx.showLoading({ title: '保存中...', mask: true }) wx.downloadFile({ url: posterQrSrc, success: (res) => { if (res.statusCode !== 200) { wx.hideLoading() wx.showToast({ title: '下载失败', icon: 'none' }) return } wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success: () => { wx.hideLoading() wx.showToast({ title: '已保存到相册', icon: 'success' }) }, fail: (err) => { wx.hideLoading() if (String(err.errMsg || '').includes('auth deny')) { wx.showModal({ title: '提示', content: '需要相册权限才能保存二维码', confirmText: '去设置', success: (r) => { if (r.confirm) wx.openSetting() } }) return } wx.showToast({ title: '保存失败', icon: 'none' }) } }) }, fail: () => { wx.hideLoading() wx.showToast({ title: '下载失败', icon: 'none' }) } }) }, // 预览二维码 previewPosterQr() { const { posterQrSrc } = this.data if (!posterQrSrc) return wx.previewImage({ urls: [posterQrSrc] }) }, // 阻止冒泡 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 availableEarnings = this.data.availableEarningsNum || 0 const minWithdrawAmount = this.data.minWithdrawAmount || 10 const hasWechatId = this.data.hasWechatId if (availableEarnings <= 0) { wx.showToast({ title: '暂无可提现收益', icon: 'none' }) return } if (availableEarnings < minWithdrawAmount) { wx.showToast({ title: `满${minWithdrawAmount}元可提现`, icon: 'none' }) return } // 未绑定微信号时引导去设置 if (!hasWechatId) { wx.showModal({ title: '请先绑定微信号', content: '提现需先绑定微信号,便于到账核对。请到「设置」中绑定后再提现。', confirmText: '去绑定', cancelText: '取消', success: (res) => { if (res.confirm) wx.navigateTo({ url: '/pages/settings/settings' }) } }) return } wx.showModal({ title: '确认提现', content: `将提现 ¥${availableEarnings.toFixed(2)} 到您的微信零钱`, confirmText: '立即提现', success: async (res) => { if (!res.confirm) return const tmplId = app.globalData.withdrawSubscribeTmplId if (tmplId && tmplId.length > 10) { wx.requestSubscribeMessage({ tmplIds: [tmplId], success: () => { this.doWithdraw(availableEarnings) }, fail: () => { this.doWithdraw(availableEarnings) } }) } else { await this.doWithdraw(availableEarnings) } } }) }, // 跳转提现记录页 goToWithdrawRecords() { wx.navigateTo({ url: '/pages/withdraw-records/withdraw-records' }) }, // 执行提现 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/miniprogram/withdraw', { method: 'POST', data: { userId, amount } }) wx.hideLoading() if (res.success) { wx.showModal({ title: '提现申请已提交 ✅', content: res.message || '正在审核中,通过后会自动到账您的微信零钱', showCancel: false, confirmText: '知道了' }) // 刷新数据(此时待审核金额会增加,可提现金额会减少) this.initData() } else { if (res.needBind || res.needBindWechat) { wx.showModal({ title: res.needBindWechat ? '请先绑定微信号' : '需要绑定微信', content: res.needBindWechat ? '请到「设置」中绑定微信号后再提现,便于到账核对。' : '请先在设置中绑定微信账号后再提现', confirmText: '去绑定', success: (modalRes) => { if (modalRes.confirm) wx.navigateTo({ url: '/pages/settings/settings' }) } }) } else { wx.showToast({ title: res.message || res.error || '提现失败', icon: 'none', duration: 3000 }) } } } 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) { this.showAutoWithdrawSettings() } else { this.showNotificationSettings() } } }) }, // 自动提现设置 async showAutoWithdrawSettings() { const app = getApp() const { userInfo } = app.globalData if (!userInfo) { wx.showToast({ title: '请先登录', icon: 'none' }) return } // 获取当前设置 let autoWithdrawEnabled = wx.getStorageSync(`autoWithdraw_${userInfo.id}`) || false let autoWithdrawThreshold = wx.getStorageSync(`autoWithdrawThreshold_${userInfo.id}`) || this.data.minWithdrawAmount || 10 wx.showModal({ title: '自动提现设置', content: `当前状态:${autoWithdrawEnabled ? '已开启' : '已关闭'}\n自动提现阈值:¥${autoWithdrawThreshold}\n\n开启后,当可提现金额达到阈值时将自动发起提现申请。`, confirmText: autoWithdrawEnabled ? '关闭' : '开启', cancelText: '修改阈值', success: (res) => { if (res.confirm) { // 切换开关 this.toggleAutoWithdraw(!autoWithdrawEnabled, autoWithdrawThreshold) } else if (res.cancel) { // 修改阈值 this.setAutoWithdrawThreshold(autoWithdrawEnabled, autoWithdrawThreshold) } } }) }, // 切换自动提现开关 toggleAutoWithdraw(enabled, threshold) { const app = getApp() const { userInfo } = app.globalData wx.setStorageSync(`autoWithdraw_${userInfo.id}`, enabled) wx.showToast({ title: enabled ? '自动提现已开启' : '自动提现已关闭', icon: 'success' }) // 如果开启,检查当前金额是否达到阈值 if (enabled && this.data.availableEarningsNum >= threshold) { wx.showModal({ title: '提示', content: `当前可提现金额¥${this.data.availableEarnings}已达到阈值¥${threshold},是否立即提现?`, success: (res) => { if (res.confirm) { this.handleWithdraw() } } }) } }, // 设置自动提现阈值 setAutoWithdrawThreshold(currentEnabled, currentThreshold) { const minAmount = this.data.minWithdrawAmount || 10 wx.showModal({ title: '设置提现阈值', content: `请输入自动提现金额阈值(最低¥${minAmount})`, editable: true, placeholderText: currentThreshold.toString(), success: (res) => { if (res.confirm && res.content) { const threshold = parseFloat(res.content) if (isNaN(threshold) || threshold < minAmount) { wx.showToast({ title: `请输入不小于¥${minAmount}的金额`, icon: 'none' }) return } const app = getApp() const { userInfo } = app.globalData wx.setStorageSync(`autoWithdrawThreshold_${userInfo.id}`, threshold) wx.showToast({ title: `阈值已设置为¥${threshold}`, icon: 'success' }) // 重新显示设置界面 setTimeout(() => { this.showAutoWithdrawSettings() }, 1500) } } }) }, // 收益通知设置 showNotificationSettings() { const app = getApp() const { userInfo } = app.globalData if (!userInfo) { wx.showToast({ title: '请先登录', icon: 'none' }) return } // 获取当前设置 let notifyEnabled = wx.getStorageSync(`earningsNotify_${userInfo.id}`) !== false // 默认开启 wx.showModal({ title: '收益通知设置', content: `当前状态:${notifyEnabled ? '已开启' : '已关闭'}\n\n开启后,将在有新收益时收到小程序通知提醒。`, confirmText: notifyEnabled ? '关闭通知' : '开启通知', success: (res) => { if (res.confirm) { const newState = !notifyEnabled wx.setStorageSync(`earningsNotify_${userInfo.id}`, newState) wx.showToast({ title: newState ? '收益通知已开启' : '收益通知已关闭', icon: 'success' }) // 如果开启,请求通知权限 if (newState) { wx.requestSubscribeMessage({ tmplIds: [''] // 需要配置模板ID }).catch(() => { // 用户拒绝授权,不影响功能 }) } } } }) }, // 分享 - 带推荐码 onShareAppMessage() { console.log('[Referral] 分享给好友,推荐码:', this.data.referralCode) return { title: 'Soul创业派对 - 来自派对房的真实商业故事', path: `/pages/index/index?ref=${this.data.referralCode}` // 不设置 imageUrl,使用小程序默认截图 // 如需自定义图片,请将图片放在 /assets/ 目录并配置路径 } }, // 分享到朋友圈 onShareTimeline() { console.log('[Referral] 分享到朋友圈,推荐码:', this.data.referralCode) return { title: `Soul创业派对 - 62个真实商业案例`, query: `ref=${this.data.referralCode}` // 不设置 imageUrl,使用小程序默认截图 } }, goBack() { wx.navigateBack() }, // 解析商品描述,获取书名和章节 parseProductDescription(description, productType) { if (!description) { return { bookTitle: '未知商品', chapterTitle: '' } } // 匹配格式:《书名》- 章节名 const match = description.match(/《(.+?)》(?:\s*-\s*(.+))?/) if (match) { return { bookTitle: match[1] || '未知书籍', chapterTitle: match[2] || (productType === 'fullbook' ? '全书购买' : '') } } // 如果匹配失败,直接返回原始描述 return { bookTitle: description.split('-')[0] || description, chapterTitle: description.split('-')[1] || '' } }, // 格式化日期 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}` } })