Files
sundynix-plant-mp/pages/profile/index.js
T
2026-05-24 01:38:28 +08:00

291 lines
8.4 KiB
JavaScript

// pages/profile/index.js
import request from '../../utils/request';
import { calculateDaysSince } from '../../utils/dateUtil';
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('/plant/profile/detail').then(res => {
if (!res) return;
// Backend returns PlantUserProfile: {nickName, avatarId, levelId, currentSunlight, ...}
// Fetch avatar URL from file service if avatarId exists
const avatarId = res.avatarId || '';
let avatarUrl = '';
if (avatarId) {
request.get('/file/' + avatarId).then(fileInfo => {
if (fileInfo && fileInfo.url) {
this.setData({ userAvatar: fileInfo.url });
}
}).catch(() => {});
}
this.setData({
userName: res.nickName || '植物爱好者',
userAvatar: avatarUrl,
currentAvatarId: avatarId,
// Stats
plantCount: res.plantCount || 0,
taskDoneCount: res.careCount || 0,
postCount: res.postCount || 0,
// Level (just store levelId, detail fetched on badges page)
userLevel: res.levelId || '',
userLevelTag: '',
// EXP / Sunlight
userExp: res.currentSunlight || 0,
userSunlight: res.currentSunlight || 0,
joinedDays: 0 // createdAt not available in profile response
});
// Update global cache
const info = { ...res, avatarId: avatarId };
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 ========
goToExchange() {
wx.navigateTo({ url: '/pages/profile/exchange/index' });
},
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) => {
}
});
},
goToAbout() {
wx.navigateTo({ url: '/pages/profile/about/index' });
},
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.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('/plant/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;
if (isAvatarChanged) {
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(...) },
})