/** * Soul创业派对 - 我的页面 * 开发: 卡若 * 技术支持: 存客宝 */ const app = getApp() Page({ data: { // 系统信息 statusBarHeight: 44, navBarHeight: 88, // 用户状态 isLoggedIn: false, userInfo: null, // 统计数据 totalSections: 62, readCount: 0, referralCount: 0, earnings: 0, pendingEarnings: 0, // 阅读统计 totalReadTime: 0, matchHistory: 0, // Tab切换 activeTab: 'overview', // overview | footprint // 最近阅读 recentChapters: [], // 功能配置 matchEnabled: false, // 找伙伴功能开关 // 菜单列表 menuList: [ { id: 'orders', title: '我的订单', icon: '📦', count: 0 }, { id: 'referral', title: '推广中心', icon: '🎁', iconBg: 'gold', badge: '90%佣金' }, { id: 'withdrawRecords', title: '提现记录', icon: '📋', iconBg: 'gray' }, { id: 'about', title: '关于作者', icon: 'ℹ️', iconBg: 'brand' }, { id: 'settings', title: '设置', icon: '⚙️', iconBg: 'gray' } ], // 待确认收款(用户确认模式) pendingConfirmList: [], withdrawMchId: '', withdrawAppId: '', // 登录弹窗 showLoginModal: false, isLoggingIn: false, // 修改昵称弹窗 showNicknameModal: false, editingNickname: '' }, onLoad() { this.setData({ statusBarHeight: app.globalData.statusBarHeight, navBarHeight: app.globalData.navBarHeight }) this.loadFeatureConfig() this.initUserStatus() }, onShow() { // 设置TabBar选中状态(根据 matchEnabled 动态设置) if (typeof this.getTabBar === 'function' && this.getTabBar()) { const tabBar = this.getTabBar() if (tabBar.updateSelected) { tabBar.updateSelected() } else { const selected = tabBar.data.matchEnabled ? 3 : 2 tabBar.setData({ selected }) } } this.initUserStatus() }, // 加载功能配置 async loadFeatureConfig() { try { const res = await app.request({ url: '/api/db/config', method: 'GET' }) if (res && res.features) { this.setData({ matchEnabled: res.features.matchEnabled === true }) } } catch (error) { console.log('加载功能配置失败:', error) // 默认关闭找伙伴功能 this.setData({ matchEnabled: false }) } }, // 初始化用户状态 initUserStatus() { const { isLoggedIn, userInfo } = app.globalData if (isLoggedIn && userInfo) { const readIds = app.globalData.readSectionIds || [] const recentList = readIds.slice(-5).reverse().map(id => ({ id: id, title: `章节 ${id}` })) const userId = userInfo.id || '' const userIdShort = userId.length > 20 ? userId.slice(0, 10) + '...' + userId.slice(-6) : userId const userWechat = wx.getStorageSync('user_wechat') || userInfo.wechat || '' // 先设基础信息;收益数据由 loadReferralEarnings 从推广中心同源接口拉取并覆盖 this.setData({ isLoggedIn: true, userInfo, userIdShort, userWechat, readCount: Math.min(app.getReadCount(), this.data.totalSections || 62), referralCount: userInfo.referralCount || 0, earnings: '0.00', pendingEarnings: '0.00', recentChapters: recentList, totalReadTime: Math.floor(Math.random() * 200) + 50 }) this.loadReferralEarnings() this.loadPendingConfirm() } else { this.setData({ isLoggedIn: false, userInfo: null, userIdShort: '', readCount: app.getReadCount(), referralCount: 0, earnings: '0.00', pendingEarnings: '0.00', recentChapters: [] }) } }, // 拉取待确认收款列表(用于「确认收款」按钮) async loadPendingConfirm() { const userInfo = app.globalData.userInfo if (!app.globalData.isLoggedIn || !userInfo || !userInfo.id) return try { const res = await app.request('/api/withdraw/pending-confirm?userId=' + userInfo.id) if (res && res.success && res.data) { const list = (res.data.list || []).map(item => ({ id: item.id, amount: (item.amount || 0).toFixed(2), package: item.package, created_at: item.created_at ? this.formatDateMy(item.created_at) : '--' })) this.setData({ pendingConfirmList: list, withdrawMchId: res.data.mch_id || '', withdrawAppId: res.data.app_id || '' }) } else { this.setData({ pendingConfirmList: [], withdrawMchId: '', withdrawAppId: '' }) } } catch (e) { this.setData({ pendingConfirmList: [] }) } }, formatDateMy(dateStr) { if (!dateStr) return '--' const d = new Date(dateStr) const m = (d.getMonth() + 1).toString().padStart(2, '0') const day = d.getDate().toString().padStart(2, '0') return `${m}-${day}` }, // 确认收款(调起微信收款页) confirmReceive(e) { const index = e.currentTarget.dataset.index const id = e.currentTarget.dataset.id const list = this.data.pendingConfirmList || [] let item = (typeof index === 'number' || (index !== undefined && index !== '')) ? list[index] : null if (!item && id) item = list.find(x => x.id === id) || null if (!item || !item.package) { wx.showToast({ title: '请稍后刷新再试', icon: 'none' }) return } const mchId = this.data.withdrawMchId const appId = this.data.withdrawAppId if (!mchId || !appId) { wx.showToast({ title: '参数缺失,请刷新重试', icon: 'none' }) return } if (!wx.canIUse('requestMerchantTransfer')) { wx.showToast({ title: '当前微信版本不支持,请升级后重试', icon: 'none' }) return } wx.showLoading({ title: '调起收款...', mask: true }) wx.requestMerchantTransfer({ mchId, appId, package: item.package, success: () => { wx.hideLoading() wx.showToast({ title: '收款成功', icon: 'success' }) const newList = list.filter(x => x.id !== item.id) this.setData({ pendingConfirmList: newList }) this.loadPendingConfirm() }, fail: (err) => { wx.hideLoading() const msg = (err.errMsg || '').includes('cancel') ? '已取消' : (err.errMsg || '收款失败') wx.showToast({ title: msg, icon: 'none' }) }, complete: () => { wx.hideLoading() } }) }, // 从与推广中心相同的接口拉取收益数据并更新展示(累计收益 = totalCommission,可提现 = 累计-已提现-待审核) async loadReferralEarnings() { const userInfo = app.globalData.userInfo if (!app.globalData.isLoggedIn || !userInfo || !userInfo.id) return const formatMoney = (num) => (typeof num === 'number' ? num.toFixed(2) : '0.00') try { const res = await app.request('/api/referral/data?userId=' + userInfo.id) if (!res || !res.success || !res.data) return const d = res.data const totalCommissionNum = d.totalCommission || 0 const withdrawnNum = d.withdrawnEarnings || 0 const pendingWithdrawNum = d.pendingWithdrawAmount || 0 const availableEarningsNum = totalCommissionNum - withdrawnNum - pendingWithdrawNum this.setData({ earnings: formatMoney(totalCommissionNum), pendingEarnings: formatMoney(availableEarningsNum), referralCount: d.referralCount || d.stats?.totalBindings || this.data.referralCount }) } catch (e) { console.log('[My] 拉取推广收益失败:', e && e.message) } }, // 微信原生获取头像(button open-type="chooseAvatar" 回调) async onChooseAvatar(e) { const tempAvatarUrl = e.detail.avatarUrl if (!tempAvatarUrl) return wx.showLoading({ title: '上传中...', mask: true }) try { // 1. 先上传图片到服务器 console.log('[My] 开始上传头像:', tempAvatarUrl) const uploadRes = await new Promise((resolve, reject) => { wx.uploadFile({ url: app.globalData.baseUrl + '/api/upload', filePath: tempAvatarUrl, name: 'file', formData: { folder: 'avatars' }, success: (res) => { try { const data = JSON.parse(res.data) if (data.success) { resolve(data) } else { reject(new Error(data.error || '上传失败')) } } catch (err) { reject(new Error('解析响应失败')) } }, fail: (err) => { reject(err) } }) }) // 2. 获取上传后的完整URL const avatarUrl = app.globalData.baseUrl + uploadRes.data.url console.log('[My] 头像上传成功:', avatarUrl) // 3. 更新本地头像 const userInfo = this.data.userInfo userInfo.avatar = avatarUrl this.setData({ userInfo }) app.globalData.userInfo = userInfo wx.setStorageSync('userInfo', userInfo) // 4. 同步到服务器数据库 await app.request('/api/user/update', { method: 'POST', data: { userId: userInfo.id, avatar: avatarUrl } }) wx.hideLoading() wx.showToast({ title: '头像更新成功', icon: 'success' }) } catch (e) { wx.hideLoading() console.error('[My] 上传头像失败:', e) wx.showToast({ title: e.message || '上传失败,请重试', icon: 'none' }) } }, // 微信原生获取昵称回调(针对 input type="nickname" 的 bindblur 或 bindchange) async handleNicknameChange(nickname) { if (!nickname || nickname === this.data.userInfo?.nickname) return try { const userInfo = this.data.userInfo userInfo.nickname = nickname this.setData({ userInfo }) app.globalData.userInfo = userInfo wx.setStorageSync('userInfo', userInfo) // 同步到服务器 await app.request('/api/user/update', { method: 'POST', data: { userId: userInfo.id, nickname } }) wx.showToast({ title: '昵称已更新', icon: 'success' }) } catch (e) { console.error('[My] 同步昵称失败:', e) } }, // 打开昵称修改弹窗 editNickname() { this.setData({ showNicknameModal: true, editingNickname: this.data.userInfo?.nickname || '' }) }, // 关闭昵称弹窗 closeNicknameModal() { this.setData({ showNicknameModal: false, editingNickname: '' }) }, // 阻止事件冒泡 stopPropagation() {}, // 昵称输入实时更新 onNicknameInput(e) { this.setData({ editingNickname: e.detail.value }) }, // 昵称变化(微信自动填充时触发) onNicknameChange(e) { const nickname = e.detail.value console.log('[My] 昵称已自动填充:', nickname) this.setData({ editingNickname: nickname }) // 自动填充时也尝试直接同步 this.handleNicknameChange(nickname) }, // 确认修改昵称 async confirmNickname() { const newNickname = this.data.editingNickname.trim() if (!newNickname) { wx.showToast({ title: '昵称不能为空', icon: 'none' }) return } if (newNickname.length < 1 || newNickname.length > 20) { wx.showToast({ title: '昵称1-20个字符', icon: 'none' }) return } // 关闭弹窗 this.closeNicknameModal() // 显示加载 wx.showLoading({ title: '更新中...', mask: true }) try { // 1. 同步到服务器 const res = await app.request('/api/user/update', { method: 'POST', data: { userId: this.data.userInfo.id, nickname: newNickname } }) if (res && res.success) { // 2. 更新本地状态 const userInfo = this.data.userInfo userInfo.nickname = newNickname this.setData({ userInfo }) // 3. 更新全局和缓存 app.globalData.userInfo = userInfo wx.setStorageSync('userInfo', userInfo) wx.hideLoading() wx.showToast({ title: '昵称已修改', icon: 'success' }) } else { throw new Error(res?.message || '更新失败') } } catch (e) { wx.hideLoading() console.error('[My] 修改昵称失败:', e) wx.showToast({ title: '修改失败,请重试', icon: 'none' }) } }, // 复制用户ID copyUserId() { const userId = this.data.userInfo?.id || '' if (!userId) { wx.showToast({ title: '暂无ID', icon: 'none' }) return } wx.setClipboardData({ data: userId, success: () => { wx.showToast({ title: 'ID已复制', icon: 'success' }) } }) }, // 切换Tab switchTab(e) { const tab = e.currentTarget.dataset.tab this.setData({ activeTab: tab }) }, // 显示登录弹窗 showLogin() { this.setData({ showLoginModal: true }) }, // 关闭登录弹窗 closeLoginModal() { if (this.data.isLoggingIn) return this.setData({ showLoginModal: false }) }, // 微信登录 async handleWechatLogin() { this.setData({ isLoggingIn: true }) try { const result = await app.login() if (result) { this.initUserStatus() this.setData({ showLoginModal: false }) wx.showToast({ title: '登录成功', icon: 'success' }) } else { wx.showToast({ title: '登录失败,请重试', icon: 'none' }) } } catch (e) { console.error('微信登录错误:', e) wx.showToast({ title: '登录失败,请重试', icon: 'none' }) } finally { this.setData({ isLoggingIn: false }) } }, // 手机号登录(需要用户授权) async handlePhoneLogin(e) { // 检查是否有授权code if (!e.detail.code) { // 用户拒绝授权或获取失败,尝试使用微信登录 console.log('手机号授权失败,尝试微信登录') return this.handleWechatLogin() } this.setData({ isLoggingIn: true }) try { const result = await app.loginWithPhone(e.detail.code) if (result) { this.initUserStatus() this.setData({ showLoginModal: false }) wx.showToast({ title: '登录成功', icon: 'success' }) } else { wx.showToast({ title: '登录失败,请重试', icon: 'none' }) } } catch (e) { console.error('手机号登录错误:', e) wx.showToast({ title: '登录失败,请重试', icon: 'none' }) } finally { this.setData({ isLoggingIn: false }) } }, // 点击菜单 handleMenuTap(e) { const id = e.currentTarget.dataset.id if (!this.data.isLoggedIn && id !== 'about') { this.showLogin() return } const routes = { orders: '/pages/purchases/purchases', referral: '/pages/referral/referral', withdrawRecords: '/pages/withdraw-records/withdraw-records', about: '/pages/about/about', settings: '/pages/settings/settings' } if (routes[id]) { wx.navigateTo({ url: routes[id] }) } }, // 跳转到阅读页 goToRead(e) { const id = e.currentTarget.dataset.id wx.navigateTo({ url: `/pages/read/read?id=${id}` }) }, // 跳转到目录 goToChapters() { wx.switchTab({ url: '/pages/chapters/chapters' }) }, // 跳转到关于页 goToAbout() { wx.navigateTo({ url: '/pages/about/about' }) }, // 跳转到匹配 goToMatch() { wx.switchTab({ url: '/pages/match/match' }) }, // 跳转到推广中心 goToReferral() { if (!this.data.isLoggedIn) { this.showLogin() return } wx.navigateTo({ url: '/pages/referral/referral' }) }, // 跳转到找伙伴页面 goToMatch() { wx.switchTab({ url: '/pages/match/match' }) }, // 退出登录 handleLogout() { wx.showModal({ title: '退出登录', content: '确定要退出登录吗?', success: (res) => { if (res.confirm) { app.logout() this.initUserStatus() wx.showToast({ title: '已退出登录', icon: 'success' }) } } }) }, // 阻止冒泡 stopPropagation() {} })