// pages/profile/index.js import request from '../../utils/request'; const app = getApp(); Page({ data: { view: 'profile', // profile, favorites, posts, about // User Info userName: '植物爱好者', userAvatar: '', userLevel: '', // Reserved for future level system userLevelTag: '', // e.g. 'Lv.4 资深植人' // Stats plantCount: 0, taskDoneCount: 0, postCount: 0, // Favorites favTab: 'all', favorites: [], filteredFavorites: [], // Posts postsTab: 'published', myPublishedPosts: [], myDrafts: [], // App version // App version appVersion: '1.0.0', scrollTop: 0 }, onLoad() { this.loadUserInfo(); }, onShow() { if (typeof this.getTabBar === 'function' && this.getTabBar()) { this.getTabBar().setData({ selected: 4 }); } // Always fetch fresh profile data this.loadUserInfo(); }, onTabItemTap() { this.setData({ view: 'profile', scrollTop: Math.random() * 0.01 }); }, // ======== User Info ======== loadUserInfo() { request.get('/profile/detail').then(res => { if (!res) return; // Map stats and level info const avatarUrl = res.avatar && res.avatar.url ? res.avatar.url : ''; const levelInfo = res.level || {}; const levelTag = levelInfo.level ? `Lv.${levelInfo.level} ${levelInfo.title || ''}` : ''; this.setData({ userName: res.nickname || '植物爱好者', userAvatar: avatarUrl, currentAvatarId: res.avatarId || (res.avatar ? res.avatar.id : ''), // Stats plantCount: res.plantCount || 0, taskDoneCount: res.careCount || 0, postCount: res.postCount || 0, // Level (if available) userLevel: levelInfo.level || 0, userLevelTag: levelTag, // EXP / Sunlight userExp: res.currentSunlight || 0 }); // Update global cache const info = { ...res, avatarId: res.avatarId || (res.avatar ? res.avatar.id : '') }; app.globalData.userInfo = info; wx.setStorageSync('userInfo', info); }).catch(err => { console.error('Load profile failed', err); }); }, // ======== Stats ======== // ======== Navigation ======== goBack() { this.setData({ view: 'profile' }); }, goToFavorites() { wx.navigateTo({ url: '/pages/profile/favorites/index' }); }, goToPosts() { wx.navigateTo({ url: '/pages/profile/posts/index' }); }, // ======== Menu Actions ======== goToIdentifyHistory() { wx.navigateTo({ url: '/pages/profile/identify-history/index' }); }, goToBadges() { wx.navigateTo({ url: '/pages/profile/badges/index' }); }, goToNotificationSettings() { // Open WeChat notification settings wx.openSetting({ success: (res) => { console.log('Settings opened', res); } }); }, goToAbout() { this.setData({ view: 'about' }); }, openDoc(e) { if (wx.openPrivacyContract) { wx.openPrivacyContract({ fail: () => { wx.showToast({ title: '无法打开协议', icon: 'none' }); } }); } else { wx.showToast({ title: '当前微信版本不支持查看', icon: 'none' }); } }, // ======== Profile Editor Popup ======== openProfileEditor() { this.setData({ showProfileEditor: true, tempAvatar: '', tempNickname: this.data.userName === '植物爱好者' ? '' : this.data.userName }); }, closeProfileEditor() { this.setData({ showProfileEditor: false }); }, onProfilePopupChange(e) { if (!e.detail.visible) { this.setData({ showProfileEditor: false }); } }, // WeChat native chooseAvatar callback onChooseAvatar(e) { const avatarUrl = e.detail.avatarUrl; if (avatarUrl) { this.setData({ tempAvatar: avatarUrl }); } }, onNicknameInput(e) { this.setData({ tempNickname: e.detail.value }); }, onNicknameBlur(e) { // WeChat nickname type may return value on blur if (e.detail.value) { this.setData({ tempNickname: e.detail.value }); } }, async saveProfile() { const { tempAvatar, tempNickname, userName, userAvatar, currentAvatarId } = this.data; // Determine if there are changes // tempNickname might be undefined if user didn't edit nickname input const finalNickname = tempNickname !== undefined ? tempNickname : userName; const isNameChanged = finalNickname !== userName; const isAvatarChanged = tempAvatar && tempAvatar !== userAvatar; if (!isNameChanged && !isAvatarChanged) { this.setData({ showProfileEditor: false }); return; } if (!finalNickname.trim()) { wx.showToast({ title: '昵称不能为空', icon: 'none' }); return; } wx.showLoading({ title: '保存中...', mask: true }); try { let finalAvatarId = currentAvatarId; // Upload new avatar if changed if (isAvatarChanged) { const uploadRes = await request.upload(tempAvatar); if (uploadRes && uploadRes.file && uploadRes.file.id) { finalAvatarId = uploadRes.file.id; } else if (uploadRes && uploadRes.id) { finalAvatarId = uploadRes.id; } else { throw new Error('Avatar upload failed, no ID returned'); } } // Construct Full Payload const updatePayload = { nickname: finalNickname, avatarId: finalAvatarId }; // Call API await request.post('/profile/update', updatePayload); // Update UI State this.setData({ userName: finalNickname, userAvatar: tempAvatar || userAvatar, currentAvatarId: finalAvatarId, showProfileEditor: false }); wx.showToast({ title: '资料已更新', icon: 'success' }); // Update Global Data const userInfo = app.globalData.userInfo || {}; userInfo.nickname = finalNickname; userInfo.name = finalNickname; // Update avatar structure in global store too if (isAvatarChanged) { userInfo.avatar = { ...(userInfo.avatar || {}), url: tempAvatar, id: finalAvatarId }; } userInfo.avatarId = finalAvatarId; app.globalData.userInfo = userInfo; wx.setStorageSync('userInfo', userInfo); } catch (err) { console.error('Save profile failed', err); wx.showToast({ title: '保存失败', icon: 'none' }); } finally { wx.hideLoading(); } }, // ======== Utilities ======== _formatTime(dateStr) { if (!dateStr) return ''; const d = new Date(dateStr); const now = new Date(); const diffMs = now - d; const diffMin = Math.floor(diffMs / 60000); if (diffMin < 1) return '刚刚'; if (diffMin < 60) return diffMin + '分钟前'; const diffHour = Math.floor(diffMin / 60); if (diffHour < 24) return diffHour + '小时前'; const diffDay = Math.floor(diffHour / 24); if (diffDay < 7) return diffDay + '天前'; const month = (d.getMonth() + 1).toString().padStart(2, '0'); const day = d.getDate().toString().padStart(2, '0'); return `${month}-${day}`; }, // ======== Reserved: Future Level/Badge System ======== // These methods will be implemented when the backend supports level/badge APIs // loadLevelInfo() { request.get('/user/level').then(...) }, // loadBadges() { request.get('/user/badges').then(...) }, })