Files
soul-yongping/miniprogram/app.js

189 lines
5.8 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: {
baseUrl: 'https://soul.quwanzhi.com',
appId: 'wxb8bbb2b10dec74aa',
userInfo: null,
openId: null,
isLoggedIn: false,
purchasedSections: [],
hasFullBook: false,
pendingReferralCode: null,
theme: {
brandColor: '#00CED1',
brandSecondary: '#20B2AA',
goldColor: '#FFD700',
bgColor: '#000000',
cardBg: '#1c1c1e'
},
systemInfo: null,
statusBarHeight: 44,
navBarHeight: 88,
capsulePaddingRight: 0,
currentTab: 0,
features: null,
matchEnabled: false,
_featureConfigLastFetch: 0
},
onLaunch(options) {
try {
this.getSystemInfo()
this.checkLoginStatus()
this.handleReferralCode(options)
// 异步请求不阻塞启动失败也不影响模拟器启动loadBookData 内部已 catch
this.loadFeatureConfig().catch(() => {})
this.loadBookData()
} catch (e) {
console.error('[App] onLaunch error', e)
}
},
onShow(options) {
this.handleReferralCode(options)
this.loadFeatureConfig()
},
loadFeatureConfig(forceRefresh) {
const now = Date.now()
const throttleMs = 15000
if (!forceRefresh && this.globalData._featureConfigLastFetch && (now - this.globalData._featureConfigLastFetch < throttleMs)) {
return Promise.resolve(this.globalData.features)
}
return this.request('/api/db/config')
.then((res) => {
if (res && res.features) {
this.globalData.features = res.features
this.globalData.matchEnabled = res.features.matchEnabled === true
this.globalData._featureConfigLastFetch = Date.now()
return this.globalData.features
}
return this.globalData.features
})
.catch((e) => {
console.log('[App] 加载功能配置失败', e)
return this.globalData.features
})
},
handleReferralCode(options) {
const query = options?.query || {}
const refCode = query.ref || query.referralCode
if (refCode) {
this.globalData.pendingReferralCode = refCode
wx.setStorageSync('pendingReferralCode', refCode)
}
},
getSystemInfo() {
try {
const systemInfo = wx.getSystemInfoSync()
this.globalData.systemInfo = systemInfo
const statusBarHeight = systemInfo.statusBarHeight || 44
this.globalData.statusBarHeight = statusBarHeight
const menuButton = wx.getMenuButtonBoundingClientRect()
if (menuButton && menuButton.top != null) {
this.globalData.navBarHeight = (menuButton.top - statusBarHeight) * 2 + menuButton.height + statusBarHeight
const w = systemInfo.windowWidth || 375
this.globalData.capsulePaddingRight = Math.ceil(w - menuButton.left + 8)
} else {
this.globalData.navBarHeight = statusBarHeight + 44
}
} 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)
}
},
loadBookData() {
this.request('/api/book/all-chapters')
.then((res) => {
if (res && res.data) {
this.globalData.bookData = res.data
wx.setStorageSync('bookData', res.data)
}
})
.catch((e) => console.error('加载书籍数据失败', e))
},
request(url, options = {}) {
return new Promise((resolve, reject) => {
const token = wx.getStorageSync('token')
const fullUrl = this.globalData.baseUrl + url
wx.request({
url: fullUrl,
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) => {
console.warn('[Request] fail', fullUrl, err)
reject(err && err.errMsg ? new Error(err.errMsg) : new Error('网络请求失败'))
}
})
})
},
async login() {
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 && res.success && res.data) {
if (res.data.openId) {
this.globalData.openId = res.data.openId
wx.setStorageSync('openId', res.data.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 || '')
}
return res.data
}
} catch (e) {
console.error('登录失败', 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')
}
})