/** * Soul创业派对 - 代付详情页 * 改造后:发起人支付,好友领取。支持单页模式引导、登录检测。 */ const app = getApp() Page({ data: { statusBarHeight: 44, requestSn: '', sectionId: '', detail: null, loading: true, paying: false, redeeming: false, isInitiator: false, requesterMsg: '', amountDisplay: '0.00', isSinglePageMode: false, showLoginModal: false, agreeProtocol: false, // 创建态 isCreateMode: false, giftQuantity: 1, unitPrice: 0 }, onLoad(options) { wx.showShareMenu({ menus: ['shareAppMessage', 'shareTimeline'] }) this.setData({ statusBarHeight: app.globalData.statusBarHeight || 44 }) if (options?.ref || options?.referralCode) { app.handleReferralCode({ query: { ref: options.ref || options.referralCode } }) } const requestSn = (options.requestSn || '').trim() const sectionId = (options.sectionId || '').trim() const isSinglePage = (wx.getSystemInfoSync?.()?.mode === 'singlePage') || app.globalData.isSinglePageMode this.setData({ requestSn, sectionId, isSinglePageMode: !!isSinglePage }) if (requestSn || sectionId) { this.loadDetail() } else { wx.showToast({ title: '链接无效', icon: 'none' }) setTimeout(() => wx.switchTab({ url: '/pages/index/index' }), 1500) } }, async loadDetail() { const { requestSn, sectionId } = this.data this.setData({ loading: true }) const userId = app.globalData.userInfo?.id || '' let url = '' if (requestSn) { url = `/api/miniprogram/gift-pay/detail?requestSn=${encodeURIComponent(requestSn)}${userId ? '&userId=' + encodeURIComponent(userId) : ''}` } else if (sectionId && userId) { url = `/api/miniprogram/gift-pay/detail?sectionId=${encodeURIComponent(sectionId)}&userId=${encodeURIComponent(userId)}` } else if (sectionId) { this.setData({ loading: false }) wx.showToast({ title: '请先登录', icon: 'none' }) return } else { this.setData({ loading: false }) return } try { const res = await app.request(url) if (res && res.success) { const isCreateMode = res.mode === 'create' || res.action === 'create' const isInitiator = res.isInitiator === true let requesterMsg = '' let amountDisplay = '0.00' if (isCreateMode) { requesterMsg = '输入发放数量,支付后分享给好友免费领取' amountDisplay = (res.unitPrice != null ? Number(res.unitPrice) * (this.data.giftQuantity || 1) : 0).toFixed(2) } else { requesterMsg = isInitiator ? (res.action === 'pay' ? '支付后分享给好友,好友打开即可免费领取。' : '分享给好友,好友打开即可免费领取。') : res.initiatorMsg || `" 请帮我代付「${res.sectionTitle || res.description || '该商品'}」,非常感谢! "` amountDisplay = (res.amount != null && res.amount !== '') ? Number(res.amount).toFixed(2) : '0.00' } this.setData({ detail: res, loading: false, isInitiator, isCreateMode, requesterMsg, amountDisplay, unitPrice: res.unitPrice != null ? res.unitPrice : 0 }) if (isCreateMode) this._updateAmountDisplay() } else { this.setData({ loading: false }) wx.showToast({ title: res?.error || '加载失败', icon: 'none' }) } } catch (e) { this.setData({ loading: false }) wx.showToast({ title: '加载失败', icon: 'none' }) } }, onGiftQuantityInput(e) { const raw = (e.detail.value || '').trim() const v = parseInt(raw, 10) this.setData({ giftQuantity: isNaN(v) ? (raw === '' ? '' : this.data.giftQuantity) : v }) this._updateAmountDisplay() }, _updateAmountDisplay() { const { unitPrice, giftQuantity } = this.data const q = Math.max(0, parseInt(giftQuantity, 10) || 0) const amount = (unitPrice || 0) * q this.setData({ amountDisplay: amount.toFixed(2) }) }, // 发起人支付(改造后:我帮别人付款) async doInitiatorPay() { if (this.data.isSinglePageMode) { wx.showModal({ title: '朋友圈单页', content: '当前为朋友圈单页,无法支付。请点击底部「前往小程序」进入完整版后再支付。', showCancel: false }) return } const userId = app.globalData.userInfo?.id || '' if (!userId) { wx.showToast({ title: '请先登录后再支付', icon: 'none' }) return } let openId = app.globalData.openId || wx.getStorageSync('openId') if (!openId) { wx.showLoading({ title: '获取支付凭证...', mask: true }) openId = await app.getOpenId() wx.hideLoading() } if (!openId) { wx.showToast({ title: '请先登录', icon: 'none' }) return } let { requestSn, sectionId, detail, giftQuantity, isCreateMode } = this.data if (!requestSn && isCreateMode && sectionId) { const q = parseInt(giftQuantity, 10) if (isNaN(q) || q !== Math.floor(q) || q < 1) { wx.showToast({ title: '发放份数须为正整数', icon: 'none' }) return } const quantity = q wx.showLoading({ title: '创建中...', mask: true }) try { const createRes = await app.request({ url: '/api/miniprogram/gift-pay/create', method: 'POST', data: { userId, productType: 'section', productId: sectionId, quantity } }) if (!createRes?.success || !createRes.requestSn) { throw new Error(createRes?.error || '创建失败') } requestSn = createRes.requestSn this.setData({ requestSn, isCreateMode: false }) } catch (e) { wx.hideLoading() wx.showToast({ title: e.message || e.error || '创建失败', icon: 'none' }) return } } if (!requestSn) return this.setData({ paying: true }) wx.showLoading({ title: '创建订单中...', mask: true }) try { const res = await app.request({ url: '/api/miniprogram/gift-pay/initiator-pay', method: 'POST', data: { requestSn, openId, userId } }) wx.hideLoading() if (!res || !res.success || !res.data?.payParams) { throw new Error(res?.error || '创建订单失败') } const payParams = res.data.payParams const orderSn = res.data.orderSn // 与正常章节支付一致:只传 5 个必需参数,不传 appId 等多余字段 await new Promise((resolve, reject) => { wx.requestPayment({ timeStamp: payParams.timeStamp, nonceStr: payParams.nonceStr, package: payParams.package, signType: payParams.signType || 'RSA', paySign: payParams.paySign, success: resolve, fail: reject }) }) wx.showToast({ title: '支付成功', icon: 'success' }) this.setData({ paying: false }) // 主动同步订单状态(与 read 页一致) if (orderSn) { try { await app.request(`/api/miniprogram/pay?orderSn=${encodeURIComponent(orderSn)}`, { silent: true }) } catch (e) { console.warn('[GiftPay] 主动同步订单失败:', e) } } this.loadDetail() } catch (e) { this.setData({ paying: false }) const msg = e.message || e.error || e.errMsg || '支付失败' if (e.errMsg && e.errMsg.includes('cancel')) { wx.showToast({ title: '已取消支付', icon: 'none' }) } else { wx.showToast({ title: msg, icon: 'none', duration: 2500 }) } } }, // 好友领取(改造后:免费获得章节) async doRedeem() { if (this.data.isSinglePageMode) { wx.showModal({ title: '朋友圈单页', content: '当前为朋友圈单页,无法登录领取。请点击底部「前往小程序」进入完整版后再领取。', showCancel: false }) return } const userId = app.globalData.userInfo?.id if (!userId) { this.setData({ showLoginModal: true, agreeProtocol: false }) return } await this._doRedeem() }, async _doRedeem() { const { requestSn } = this.data const userId = app.globalData.userInfo?.id if (!requestSn || !userId) return this.setData({ redeeming: true }) wx.showLoading({ title: '领取中...', mask: true }) try { const res = await app.request({ url: '/api/miniprogram/gift-pay/redeem', method: 'POST', data: { requestSn, userId } }) wx.hideLoading() this.setData({ redeeming: false }) if (res && res.success) { wx.showToast({ title: '领取成功', icon: 'success' }) const mid = res.sectionMid || res.sectionId const q = mid ? `mid=${mid}` : `id=${res.sectionId || ''}` setTimeout(() => { wx.navigateTo({ url: `/pages/read/read?${q}` }) }, 800) } else { wx.showToast({ title: res?.error || '领取失败', icon: 'none' }) } } catch (e) { this.setData({ redeeming: false }) wx.hideLoading() wx.showToast({ title: e.message || e.error || '领取失败', icon: 'none' }) } }, closeLoginModal() { this.setData({ showLoginModal: false }) }, toggleAgree() { this.setData({ agreeProtocol: !this.data.agreeProtocol }) }, async handleWechatLogin() { if (!this.data.agreeProtocol) { wx.showToast({ title: '请先阅读并同意用户协议和隐私政策', icon: 'none' }) return } try { const result = await app.login() if (!result) return this.setData({ showLoginModal: false, agreeProtocol: false }) await this._doRedeem() } catch (e) { wx.showToast({ title: '登录失败', icon: 'none' }) } }, async handlePhoneLogin(e) { if (!e.detail.code) return this.handleWechatLogin() try { const result = await app.loginWithPhone(e.detail.code) if (!result) return this.setData({ showLoginModal: false }) await this._doRedeem() } catch (e) { wx.showToast({ title: '登录失败', icon: 'none' }) } }, stopPropagation() {}, openUserProtocol() { wx.navigateTo({ url: '/pages/agreement/agreement' }) }, openPrivacy() { wx.navigateTo({ url: '/pages/privacy/privacy' }) }, goBack() { app.goBackOrToHome() }, goToInitiatorProfile() { const { detail } = this.data if (!detail?.initiatorUserId) return wx.navigateTo({ url: `/pages/member-detail/member-detail?id=${detail.initiatorUserId}` }) }, goToArticle() { const { detail } = this.data if (!detail || detail.productType !== 'section' || !detail.productId) return const mid = detail.productMid const q = mid ? `mid=${mid}` : `id=${detail.productId}` wx.navigateTo({ url: `/pages/read/read?${q}` }) }, onShareAppMessage() { const { requestSn } = this.data const ref = app.getMyReferralCode?.() || app.globalData.userInfo?.referralCode || '' let path = '/pages/gift-pay/detail' const params = [] if (requestSn) params.push(`requestSn=${encodeURIComponent(requestSn)}`) if (ref) params.push(`ref=${encodeURIComponent(ref)}`) if (params.length) path += '?' + params.join('&') return { title: '好友送你一篇好文 - Soul创业派对', path } }, onShareTimeline() { const { requestSn } = this.data const ref = app.getMyReferralCode?.() || app.globalData.userInfo?.referralCode || '' const params = [] if (requestSn) params.push(`requestSn=${encodeURIComponent(requestSn)}`) if (ref) params.push(`ref=${encodeURIComponent(ref)}`) return { title: '好友送你一篇好文 - Soul创业派对', query: params.length ? params.join('&') : '' } } })