Files
soul-yongping/miniprogram/app.js
卡若 395501e961 fix: 修复分销数据不显示和用户ID唯一性问题
1. 分销数据修复:
   - 添加访问记录API,即使未登录也记录访问
   - 登录成功后自动绑定推荐码
   - 在链接访问时立即记录访问统计

2. 支付商品名称修复:
   - 支付时显示完整章节名称而非仅ID
   - 格式:章节9.12-美业整合:一个人的公司如何月入十万

3. 用户ID唯一性修复:
   - 移除mockLogin,必须使用真实微信登录
   - 用户ID使用openId作为唯一标识
   - 同一微信用户每次登录都是同一ID
2026-01-29 11:11:58 +08:00

465 lines
13 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.

/**
* Soul创业派对 - 小程序入口
* 开发: 卡若
*/
App({
globalData: {
// API基础地址 - 连接真实后端
baseUrl: 'https://soul.quwanzhi.com',
// 小程序配置 - 真实AppID
appId: 'wxb8bbb2b10dec74aa',
// 微信支付配置
mchId: '1318592501', // 商户号
// 用户信息
userInfo: null,
openId: null, // 微信openId支付必需
isLoggedIn: false,
// 书籍数据
bookData: null,
totalSections: 62,
// 购买记录
purchasedSections: [],
hasFullBook: false,
// 推荐绑定
pendingReferralCode: null, // 待绑定的推荐码
// 主题配置
theme: {
brandColor: '#00CED1',
brandSecondary: '#20B2AA',
goldColor: '#FFD700',
bgColor: '#000000',
cardBg: '#1c1c1e'
},
// 系统信息
systemInfo: null,
statusBarHeight: 44,
navBarHeight: 88,
// TabBar相关
currentTab: 0
},
onLaunch(options) {
// 获取系统信息
this.getSystemInfo()
// 检查登录状态
this.checkLoginStatus()
// 加载书籍数据
this.loadBookData()
// 检查更新
this.checkUpdate()
// 处理分享参数(推荐码绑定)
this.handleReferralCode(options)
},
// 小程序显示时也检查分享参数
onShow(options) {
this.handleReferralCode(options)
},
// 处理推荐码绑定
handleReferralCode(options) {
const query = options?.query || {}
const refCode = query.ref || query.referralCode
if (refCode) {
console.log('[App] 检测到推荐码:', refCode)
// 立即记录访问(不需要登录,用于统计"通过链接进的人数"
this.recordReferralVisit(refCode)
// 检查是否已经绑定过
const boundRef = wx.getStorageSync('boundReferralCode')
if (boundRef && boundRef !== refCode) {
console.log('[App] 已绑定过其他推荐码,不更换绑定关系')
// 但仍然记录访问不return
} else {
// 保存待绑定的推荐码
this.globalData.pendingReferralCode = refCode
wx.setStorageSync('pendingReferralCode', refCode)
// 如果已登录,立即绑定
if (this.globalData.isLoggedIn && this.globalData.userInfo) {
this.bindReferralCode(refCode)
}
}
}
},
// 记录推荐访问(不需要登录,用于统计)
async recordReferralVisit(refCode) {
try {
// 获取openId如果有
const openId = this.globalData.openId || wx.getStorageSync('openId') || ''
const userId = this.globalData.userInfo?.id || ''
await this.request('/api/referral/visit', {
method: 'POST',
data: {
referralCode: refCode,
visitorOpenId: openId,
visitorId: userId,
source: 'miniprogram',
page: getCurrentPages()[getCurrentPages().length - 1]?.route || ''
}
})
console.log('[App] 记录推荐访问成功')
} catch (e) {
console.log('[App] 记录推荐访问失败:', e.message)
// 忽略错误,不影响用户体验
}
},
// 绑定推荐码到用户
async bindReferralCode(refCode) {
try {
const userId = this.globalData.userInfo?.id
if (!userId || !refCode) return
// 检查是否已绑定
const boundRef = wx.getStorageSync('boundReferralCode')
if (boundRef) {
console.log('[App] 已绑定推荐码,跳过')
return
}
console.log('[App] 绑定推荐码:', refCode, '到用户:', userId)
// 调用API绑定推荐关系
const res = await this.request('/api/referral/bind', {
method: 'POST',
data: {
userId,
referralCode: refCode
}
})
if (res.success) {
console.log('[App] 推荐码绑定成功')
wx.setStorageSync('boundReferralCode', refCode)
this.globalData.pendingReferralCode = null
wx.removeStorageSync('pendingReferralCode')
}
} catch (e) {
console.error('[App] 绑定推荐码失败:', e)
}
},
// 获取系统信息
getSystemInfo() {
try {
const systemInfo = wx.getSystemInfoSync()
this.globalData.systemInfo = systemInfo
this.globalData.statusBarHeight = systemInfo.statusBarHeight || 44
// 计算导航栏高度
const menuButton = wx.getMenuButtonBoundingClientRect()
if (menuButton) {
this.globalData.navBarHeight = (menuButton.top - systemInfo.statusBarHeight) * 2 + menuButton.height + systemInfo.statusBarHeight
}
} catch (e) {
console.error('获取系统信息失败:', e)
}
},
// 检查登录状态
checkLoginStatus() {
try {
const userInfo = wx.getStorageSync('userInfo')
const token = wx.getStorageSync('token')
if (userInfo && token) {
this.globalData.userInfo = userInfo
this.globalData.isLoggedIn = true
this.globalData.purchasedSections = userInfo.purchasedSections || []
this.globalData.hasFullBook = userInfo.hasFullBook || false
}
} catch (e) {
console.error('检查登录状态失败:', e)
}
},
// 加载书籍数据
async loadBookData() {
try {
// 先从缓存加载
const cachedData = wx.getStorageSync('bookData')
if (cachedData) {
this.globalData.bookData = cachedData
}
// 从服务器获取最新数据
const res = await this.request('/api/book/all-chapters')
if (res && res.data) {
this.globalData.bookData = res.data
wx.setStorageSync('bookData', res.data)
}
} catch (e) {
console.error('加载书籍数据失败:', e)
}
},
// 检查更新
checkUpdate() {
if (wx.canIUse('getUpdateManager')) {
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate((res) => {
if (res.hasUpdate) {
console.log('发现新版本')
}
})
updateManager.onUpdateReady(() => {
wx.showModal({
title: '更新提示',
content: '新版本已准备好,是否重启应用?',
success: (res) => {
if (res.confirm) {
updateManager.applyUpdate()
}
}
})
})
updateManager.onUpdateFailed(() => {
wx.showToast({
title: '更新失败,请稍后重试',
icon: 'none'
})
})
}
},
// 统一请求方法
request(url, options = {}) {
return new Promise((resolve, reject) => {
const token = wx.getStorageSync('token')
wx.request({
url: this.globalData.baseUrl + url,
method: options.method || 'GET',
data: options.data || {},
header: {
'Content-Type': 'application/json',
'Authorization': token ? `Bearer ${token}` : '',
...options.header
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data)
} else if (res.statusCode === 401) {
// 未授权,清除登录状态
this.logout()
reject(new Error('未授权'))
} else {
reject(new Error(res.data?.message || '请求失败'))
}
},
fail: (err) => {
reject(err)
}
})
})
},
// 登录方法 - 获取openId用于支付
async login() {
try {
// 获取微信登录code
const loginRes = await new Promise((resolve, reject) => {
wx.login({
success: resolve,
fail: reject
})
})
console.log('[App] 获取登录code成功')
try {
// 发送code到服务器获取openId
const res = await this.request('/api/miniprogram/login', {
method: 'POST',
data: { code: loginRes.code }
})
if (res.success && res.data) {
// 保存openId
if (res.data.openId) {
this.globalData.openId = res.data.openId
wx.setStorageSync('openId', res.data.openId)
console.log('[App] 获取openId成功')
}
// 保存用户信息
if (res.data.user) {
this.globalData.userInfo = res.data.user
this.globalData.isLoggedIn = true
this.globalData.purchasedSections = res.data.user.purchasedSections || []
this.globalData.hasFullBook = res.data.user.hasFullBook || false
wx.setStorageSync('userInfo', res.data.user)
wx.setStorageSync('token', res.data.token || '')
// 登录成功后,检查待绑定的推荐码并执行绑定
const pendingRef = wx.getStorageSync('pendingReferralCode') || this.globalData.pendingReferralCode
if (pendingRef) {
console.log('[App] 登录后自动绑定推荐码:', pendingRef)
this.bindReferralCode(pendingRef)
}
}
return res.data
}
} catch (apiError) {
console.log('[App] API登录失败:', apiError.message)
// 不使用模拟登录,提示用户网络问题
wx.showToast({ title: '网络异常,请重试', icon: 'none' })
return null
}
return null
} catch (e) {
console.error('[App] 登录失败:', e)
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
return null
}
},
// 获取openId (支付必需)
async getOpenId() {
// 先检查缓存
const cachedOpenId = wx.getStorageSync('openId')
if (cachedOpenId) {
this.globalData.openId = cachedOpenId
return cachedOpenId
}
// 没有缓存则登录获取
try {
const loginRes = await new Promise((resolve, reject) => {
wx.login({ success: resolve, fail: reject })
})
const res = await this.request('/api/miniprogram/login', {
method: 'POST',
data: { code: loginRes.code }
})
if (res.success && res.data?.openId) {
this.globalData.openId = res.data.openId
wx.setStorageSync('openId', res.data.openId)
return res.data.openId
}
} catch (e) {
console.error('[App] 获取openId失败:', e)
}
return null
},
// 模拟登录已废弃 - 不再使用
// 现在必须使用真实的微信登录获取openId作为唯一标识
mockLogin() {
console.warn('[App] mockLogin已废弃请使用真实登录')
return null
},
// 手机号登录
async loginWithPhone(phoneCode) {
try {
// 尝试API登录
const res = await this.request('/api/wechat/phone-login', {
method: 'POST',
data: { code: phoneCode }
})
if (res.success && res.data) {
this.globalData.userInfo = res.data.user
this.globalData.isLoggedIn = true
this.globalData.purchasedSections = res.data.user.purchasedSections || []
this.globalData.hasFullBook = res.data.user.hasFullBook || false
wx.setStorageSync('userInfo', res.data.user)
wx.setStorageSync('token', res.data.token)
// 登录成功后绑定推荐码
const pendingRef = wx.getStorageSync('pendingReferralCode') || this.globalData.pendingReferralCode
if (pendingRef) {
console.log('[App] 手机号登录后自动绑定推荐码:', pendingRef)
this.bindReferralCode(pendingRef)
}
return res.data
}
} catch (e) {
console.log('[App] 手机号登录失败:', e)
wx.showToast({ title: '登录失败,请重试', icon: 'none' })
}
return null
},
// 退出登录
logout() {
this.globalData.userInfo = null
this.globalData.isLoggedIn = false
this.globalData.purchasedSections = []
this.globalData.hasFullBook = false
wx.removeStorageSync('userInfo')
wx.removeStorageSync('token')
},
// 检查是否已购买章节
hasPurchased(sectionId) {
if (this.globalData.hasFullBook) return true
return this.globalData.purchasedSections.includes(sectionId)
},
// 获取章节总数
getTotalSections() {
return this.globalData.totalSections
},
// 切换TabBar
switchTab(index) {
this.globalData.currentTab = index
},
// 显示Toast
showToast(title, icon = 'none') {
wx.showToast({
title,
icon,
duration: 2000
})
},
// 显示Loading
showLoading(title = '加载中...') {
wx.showLoading({
title,
mask: true
})
},
// 隐藏Loading
hideLoading() {
wx.hideLoading()
}
})