2026-03-06 12:12:13 +08:00
|
|
|
|
import accessManager from '../../utils/chapterAccessManager'
|
2026-02-23 14:07:41 +08:00
|
|
|
|
const app = getApp()
|
2026-03-17 18:22:06 +08:00
|
|
|
|
const { trackClick } = require('../../utils/trackClick')
|
2026-02-23 14:07:41 +08:00
|
|
|
|
|
|
|
|
|
|
Page({
|
|
|
|
|
|
data: {
|
|
|
|
|
|
statusBarHeight: 44,
|
|
|
|
|
|
isVip: false,
|
|
|
|
|
|
daysRemaining: 0,
|
|
|
|
|
|
expireDateStr: '',
|
|
|
|
|
|
price: 1980,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
originalPrice: 6980,
|
2026-02-28 15:16:23 +08:00
|
|
|
|
/* 按 premium_membership_landing_v1 设计稿 */
|
2026-02-24 14:35:58 +08:00
|
|
|
|
contentRights: [
|
2026-03-18 16:00:57 +08:00
|
|
|
|
{ title: '解锁全部章节', desc: '365天全案精读', icon: 'book-open' },
|
|
|
|
|
|
{ title: '案例库', desc: '100+创业实战案例', icon: 'book-open' },
|
|
|
|
|
|
{ title: '智能纪要', desc: 'AI每日精华推送', icon: 'lightbulb' },
|
|
|
|
|
|
{ title: '会议纪要库', desc: '往期完整沉淀', icon: 'folder' }
|
2026-02-24 14:35:58 +08:00
|
|
|
|
],
|
|
|
|
|
|
socialRights: [
|
2026-03-18 16:00:57 +08:00
|
|
|
|
{ title: '匹配创业伙伴', desc: '精准人脉匹配', icon: 'users' },
|
|
|
|
|
|
{ title: '创业老板排行', desc: '项目曝光展示', icon: 'bar-chart' },
|
|
|
|
|
|
{ title: '链接资源', desc: '深度私域资源池', icon: 'link' },
|
2026-03-18 17:01:26 +08:00
|
|
|
|
{ title: '专属VIP标识', desc: '金色尊享光圈', icon: 'check' }
|
2026-02-24 14:35:58 +08:00
|
|
|
|
],
|
2026-02-23 14:07:41 +08:00
|
|
|
|
purchasing: false
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onLoad() {
|
2026-02-27 14:22:58 +08:00
|
|
|
|
wx.showShareMenu({ withShareTimeline: true })
|
2026-02-23 14:07:41 +08:00
|
|
|
|
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
|
|
|
|
|
|
this.loadVipInfo()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
async loadVipInfo() {
|
|
|
|
|
|
const userId = app.globalData.userInfo?.id
|
|
|
|
|
|
if (!userId) return
|
|
|
|
|
|
try {
|
2026-02-25 11:50:07 +08:00
|
|
|
|
const res = await app.request({ url: `/api/miniprogram/vip/status?userId=${userId}`, silent: true })
|
2026-02-23 14:07:41 +08:00
|
|
|
|
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')}`
|
|
|
|
|
|
}
|
2026-03-10 18:06:10 +08:00
|
|
|
|
// 同步 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)
|
|
|
|
|
|
|
2026-02-23 14:07:41 +08:00
|
|
|
|
this.setData({
|
2026-03-10 18:06:10 +08:00
|
|
|
|
isVip,
|
2026-02-23 14:07:41 +08:00
|
|
|
|
daysRemaining: d.daysRemaining,
|
|
|
|
|
|
expireDateStr: expStr,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
price: d.price || 1980
|
2026-02-23 14:07:41 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-02-24 14:35:58 +08:00
|
|
|
|
} catch (e) { console.log('[VIP] 加载失败', e) }
|
2026-02-23 14:07:41 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
async handlePurchase() {
|
2026-03-17 18:22:06 +08:00
|
|
|
|
trackClick('vip', 'btn_click', '开通VIP')
|
2026-02-24 14:35:58 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-03-18 20:33:50 +08:00
|
|
|
|
// 支付前:若头像/昵称仍为默认值,引导先完善(仅头像+昵称)
|
|
|
|
|
|
if (this._shouldGuideAvatarNickname()) {
|
|
|
|
|
|
wx.showModal({
|
|
|
|
|
|
title: '完善资料',
|
|
|
|
|
|
content: '开通超级个体前,请先设置头像和昵称,让他人更好地认识你',
|
|
|
|
|
|
confirmText: '去完善',
|
|
|
|
|
|
cancelText: '稍后',
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
if (res.confirm) wx.navigateTo({ url: '/pages/avatar-nickname/avatar-nickname' })
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-23 14:07:41 +08:00
|
|
|
|
this.setData({ purchasing: true })
|
2026-03-17 11:44:36 +08:00
|
|
|
|
const amount = this.data.price
|
2026-02-23 14:07:41 +08:00
|
|
|
|
try {
|
2026-03-17 11:44:36 +08:00
|
|
|
|
// 0. 尝试余额支付(若余额足够)
|
|
|
|
|
|
const referralCode = wx.getStorageSync('referral_code') || ''
|
|
|
|
|
|
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. 微信支付
|
2026-02-24 14:35:58 +08:00
|
|
|
|
const payRes = await app.request('/api/miniprogram/pay', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
data: {
|
|
|
|
|
|
openId,
|
|
|
|
|
|
userId,
|
|
|
|
|
|
productType: 'vip',
|
|
|
|
|
|
productId: 'vip_annual',
|
2026-03-17 11:44:36 +08:00
|
|
|
|
amount,
|
2026-02-24 14:35:58 +08:00
|
|
|
|
description: '卡若创业派对VIP年度会员(365天)'
|
2026-02-23 14:07:41 +08:00
|
|
|
|
}
|
2026-02-24 14:35:58 +08:00
|
|
|
|
})
|
|
|
|
|
|
if (payRes?.success && payRes.data?.payParams) {
|
|
|
|
|
|
wx.requestPayment({
|
|
|
|
|
|
...payRes.data.payParams,
|
2026-03-06 12:12:13 +08:00
|
|
|
|
success: async () => {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
wx.showToast({ title: 'VIP开通成功', icon: 'success' })
|
2026-03-06 12:12:13 +08:00
|
|
|
|
await this._onVipPaymentSuccess()
|
2026-02-24 14:35:58 +08:00
|
|
|
|
},
|
|
|
|
|
|
fail: () => wx.showToast({ title: '支付取消', icon: 'none' })
|
|
|
|
|
|
})
|
2026-02-23 14:07:41 +08:00
|
|
|
|
} else {
|
2026-02-24 14:35:58 +08:00
|
|
|
|
wx.showToast({ title: payRes?.error || '支付参数获取失败', icon: 'none' })
|
2026-02-23 14:07:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('[VIP] 购买失败', e)
|
2026-02-24 14:35:58 +08:00
|
|
|
|
wx.showToast({ title: '购买失败,请稍后重试', icon: 'none' })
|
2026-02-23 14:07:41 +08:00
|
|
|
|
} finally { this.setData({ purchasing: false }) }
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-06 12:12:13 +08:00
|
|
|
|
async _onVipPaymentSuccess() {
|
|
|
|
|
|
wx.showLoading({ title: '同步权益中...', mask: true })
|
|
|
|
|
|
try {
|
|
|
|
|
|
await new Promise(r => setTimeout(r, 1500))
|
|
|
|
|
|
await accessManager.refreshUserPurchaseStatus()
|
2026-03-10 18:06:10 +08:00
|
|
|
|
// 重新拉取 VIP 状态并同步到全局
|
2026-03-06 12:12:13 +08:00
|
|
|
|
await this.loadVipInfo()
|
|
|
|
|
|
const pages = getCurrentPages()
|
|
|
|
|
|
pages.forEach(p => {
|
|
|
|
|
|
if (typeof p.initUserStatus === 'function') p.initUserStatus()
|
|
|
|
|
|
else if (typeof p.updateUserStatus === 'function') p.updateUserStatus()
|
|
|
|
|
|
})
|
2026-03-18 20:33:50 +08:00
|
|
|
|
|
|
|
|
|
|
// 开通成功后兜底:仍为默认头像/昵称则引导完善
|
|
|
|
|
|
if (this._shouldGuideAvatarNickname()) {
|
|
|
|
|
|
wx.navigateTo({ url: '/pages/avatar-nickname/avatar-nickname' })
|
|
|
|
|
|
}
|
2026-03-06 12:12:13 +08:00
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('[VIP] 支付后同步失败:', e)
|
|
|
|
|
|
}
|
|
|
|
|
|
wx.hideLoading()
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-18 20:33:50 +08:00
|
|
|
|
_shouldGuideAvatarNickname() {
|
|
|
|
|
|
const user = app.globalData.userInfo || {}
|
|
|
|
|
|
const avatar = (user.avatar || user.avatarUrl || '').trim()
|
|
|
|
|
|
const nickname = (user.nickname || user.nickName || '').trim()
|
|
|
|
|
|
// 与 ruleEngine.checkRule_FillAvatar 保持同口径(允许前端兜底)
|
|
|
|
|
|
if (avatar && !avatar.includes('default') && nickname && nickname !== '微信用户' && !nickname.startsWith('微信用户')) return false
|
|
|
|
|
|
return true
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2026-03-06 15:16:19 +08:00
|
|
|
|
goBack() { getApp().goBackOrToHome() },
|
2026-02-25 11:47:36 +08:00
|
|
|
|
|
|
|
|
|
|
onShareAppMessage() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
|
|
|
|
|
return {
|
|
|
|
|
|
title: 'Soul创业派对 - VIP会员',
|
|
|
|
|
|
path: ref ? `/pages/vip/vip?ref=${ref}` : '/pages/vip/vip'
|
|
|
|
|
|
}
|
2026-02-27 14:22:58 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onShareTimeline() {
|
|
|
|
|
|
const ref = app.getMyReferralCode()
|
|
|
|
|
|
return { title: 'Soul创业派对 - VIP会员', query: ref ? `ref=${ref}` : '' }
|
2026-02-25 11:47:36 +08:00
|
|
|
|
}
|
2026-02-23 14:07:41 +08:00
|
|
|
|
})
|