/** * 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') } })