Files
soul-yongping/miniprogram/pages/vip/vip.js
Alex-larget dcb7961945 Merge branch 'devlop' into yongxu-dev
# Conflicts:
#	miniprogram/app.js   resolved by devlop version
#	miniprogram/pages/chapters/chapters.js   resolved by devlop version
#	miniprogram/pages/match/match.js   resolved by devlop version
#	miniprogram/pages/member-detail/member-detail.js   resolved by devlop version
#	miniprogram/pages/my/my.js   resolved by devlop version
#	miniprogram/pages/read/read.js   resolved by devlop version
#	miniprogram/pages/referral/referral.js   resolved by devlop version
#	soul-api/internal/model/person.go   resolved by devlop version
2026-03-24 15:44:56 +08:00

226 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const accessManager = require('../../utils/chapterAccessManager')
const soulBridge = require('../../utils/soulBridge.js')
const app = getApp()
const { trackClick } = require('../../utils/trackClick')
Page({
data: {
statusBarHeight: 44,
isVip: false,
daysRemaining: 0,
expireDateStr: '',
price: 1980,
originalPrice: 6980,
/* 按 premium_membership_landing_v1 设计稿 */
contentRights: [
{ key: 'match', title: '匹配伙伴', desc: '精准匹配创业伙伴', icon: 'users' },
{ key: 'party', title: '派对专属', desc: '创业派对房专享', icon: 'star' },
{ key: 'rank', title: '老板排行', desc: '创业老板排行榜', icon: 'bar-chart' },
{ key: 'top', title: '轮流置顶', desc: '首页获客曝光位', icon: 'chevron-up' }
],
socialRights: [
{ key: 'cases', title: '案例宝库', desc: '100+赚钱案例库', icon: 'book-open' },
{ key: 'fullbook', title: '全书解锁', desc: '365天全案精读', icon: 'folder' },
{ key: 'daily', title: '每日总结', desc: 'AI每日精华推送', icon: 'lightbulb' },
{ key: 'leads', title: '获取客资', desc: '文章@你即可获客', icon: 'link' }
],
purchasing: false
},
onLoad() {
wx.showShareMenu({ withShareTimeline: true })
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
this.loadVipInfo()
},
async loadVipInfo() {
const userId = app.globalData.userInfo?.id
if (!userId) return
try {
const res = await app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true })
if (res?.success) {
const d = res.data
let expStr = ''
if (d.expireDate) {
const dt = new Date(d.expireDate)
expStr = `${dt.getFullYear()}-${String(dt.getMonth()+1).padStart(2,'0')}-${String(dt.getDate()).padStart(2,'0')}`
}
// 同步 VIP 状态到全局(与「我的」页保持一致)
const isVip = !!d.isVip
app.globalData.isVip = isVip
app.globalData.vipExpireDate = d.expireDate || expStr || ''
const userInfo = app.globalData.userInfo || {}
userInfo.isVip = isVip
userInfo.vipExpireDate = app.globalData.vipExpireDate
app.globalData.userInfo = userInfo
wx.setStorageSync('userInfo', userInfo)
this.setData({
isVip,
daysRemaining: d.daysRemaining,
expireDateStr: expStr,
price: d.price || 1980
})
}
} catch (e) { console.log('[VIP] 加载失败', e) }
},
async handlePurchase() {
trackClick('vip', 'btn_click', '开通VIP')
let userId = app.globalData.userInfo?.id
let openId = app.globalData.openId || app.globalData.userInfo?.open_id
if (!userId || !openId) {
wx.showLoading({ title: '登录中...', mask: true })
try {
await app.login()
userId = app.globalData.userInfo?.id
openId = app.globalData.openId || app.globalData.userInfo?.open_id
wx.hideLoading()
if (!userId || !openId) {
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
return
}
} catch (e) {
wx.hideLoading()
wx.showToast({ title: '登录失败', icon: 'none' })
return
}
}
// VIP 购买成功后再跳转资料页:购买前不拦截
this.setData({ purchasing: true })
const amount = this.data.price
try {
// 0. 尝试余额支付(若余额足够)
const referralCode = soulBridge.getReferralCodeForPay(app)
try {
const balanceRes = await app.request({ url: `/api/miniprogram/balance?userId=${userId}`, silent: true })
const balance = balanceRes?.data?.balance || 0
if (balance >= amount) {
const consumeRes = await app.request({
url: '/api/miniprogram/balance/consume',
method: 'POST',
data: {
userId,
productType: 'vip',
productId: 'vip_annual',
amount,
referralCode: referralCode || undefined
}
})
if (consumeRes?.success) {
this.setData({ purchasing: false })
wx.showToast({ title: 'VIP开通成功', icon: 'success' })
await this._onVipPaymentSuccess()
return
}
}
} catch (e) {
console.warn('[VIP] 余额支付失败,改用微信支付:', e)
}
// 1. 微信支付(带推荐码,与章节/匹配支付一致,便于分销归因)
const payRes = await app.request('/api/miniprogram/pay', {
method: 'POST',
data: {
openId,
userId,
productType: 'vip',
productId: 'vip_annual',
amount,
description: '卡若创业派对VIP年度会员365天',
referralCode: soulBridge.getReferralCodeForPay(app) || undefined
}
})
if (payRes?.success && payRes.data?.payParams) {
try {
await soulBridge.requestWxJsapiPayment(payRes.data.payParams)
await soulBridge.syncOrderStatusQuery(app, payRes.data.orderSn)
wx.showToast({ title: 'VIP开通成功', icon: 'success' })
await this._onVipPaymentSuccess()
} catch (e) {
const msg = (e && e.errMsg) ? String(e.errMsg) : ''
if (msg.indexOf('cancel') !== -1) wx.showToast({ title: '支付取消', icon: 'none' })
else wx.showToast({ title: '支付失败', icon: 'none' })
}
} else {
wx.showToast({ title: payRes?.error || '支付参数获取失败', icon: 'none' })
}
} catch (e) {
console.error('[VIP] 购买失败', e)
wx.showToast({ title: '购买失败,请稍后重试', icon: 'none' })
} finally { this.setData({ purchasing: false }) }
},
async _onVipPaymentSuccess() {
wx.showLoading({ title: '同步权益中...', mask: true })
try {
await new Promise(r => setTimeout(r, 1500))
await accessManager.refreshUserPurchaseStatus()
// 重新拉取 VIP 状态并同步到全局
await this.loadVipInfo()
const pages = getCurrentPages()
pages.forEach(p => {
if (typeof p.initUserStatus === 'function') p.initUserStatus()
else if (typeof p.updateUserStatus === 'function') p.updateUserStatus()
})
// 超级个体购买后:弹窗提示,强制跳转资料编辑页
wx.hideLoading()
wx.showModal({
title: '补全 VIP 资料',
content: '补全资料后,找伙伴、提现与 VIP 群对接会更顺畅;手机号等为必填项。',
confirmText: '去填写',
showCancel: false,
success: () => {
wx.redirectTo({ url: '/pages/profile-edit/profile-edit?from=vip' })
}
})
} catch (e) {
console.error('[VIP] 支付后同步失败:', e)
wx.hideLoading()
}
},
goBack() { getApp().goBackOrToHome() },
/**
* 权益卡片跳转:会员权利 / 派对权利 统一点击进对应能力页
*/
onBenefitTap(e) {
const key = e.currentTarget.dataset.key
if (!key) return
trackClick('vip', 'benefit_tap', key)
const tab = (path) => {
wx.switchTab({ url: path })
}
const nav = (path) => {
wx.navigateTo({ url: path })
}
const routes = {
match: () => tab('/pages/match/match'),
party: () => nav('/pages/mentors/mentors'),
rank: () => tab('/pages/index/index'),
top: () => tab('/pages/index/index'),
cases: () => tab('/pages/chapters/chapters'),
fullbook: () => tab('/pages/chapters/chapters'),
daily: () => tab('/pages/chapters/chapters'),
leads: () => nav('/pages/profile-edit/profile-edit')
}
const fn = routes[key]
if (typeof fn === 'function') fn()
},
onShareAppMessage() {
const ref = app.getMyReferralCode()
return {
title: '卡若创业派对 - VIP会员',
path: ref ? `/pages/vip/vip?ref=${ref}` : '/pages/vip/vip'
}
},
onShareTimeline() {
const ref = app.getMyReferralCode()
return { title: '卡若创业派对 - VIP会员', query: ref ? `ref=${ref}` : '' }
}
})