feat: 样式修改
This commit is contained in:
+294
-78
@@ -1,52 +1,163 @@
|
||||
// pages/profile/index.js
|
||||
import { MOCK_FAVORITES, MOCK_BADGES, MOCK_POSTS } from '../../utils/mockData';
|
||||
import request from '../../utils/request';
|
||||
|
||||
const app = getApp();
|
||||
|
||||
Page({
|
||||
data: {
|
||||
view: 'profile', // profile, favorites, posts, badges
|
||||
favTab: 'all', // all, plant, article
|
||||
postsTab: 'published', // published, drafts
|
||||
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: [],
|
||||
badges: []
|
||||
|
||||
// App version
|
||||
appVersion: '1.0.0'
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
this.setData({
|
||||
favorites: MOCK_FAVORITES,
|
||||
badges: MOCK_BADGES
|
||||
});
|
||||
this.filterFavorites();
|
||||
onLoad() {
|
||||
this.loadUserInfo();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (typeof this.getTabBar === 'function' &&
|
||||
this.getTabBar()) {
|
||||
this.getTabBar().setData({
|
||||
selected: 4 // Index 4 is Profile
|
||||
})
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
this.getTabBar().setData({ selected: 4 });
|
||||
}
|
||||
|
||||
// Refresh posts data
|
||||
this.loadMyPosts();
|
||||
this.loadDrafts();
|
||||
},
|
||||
|
||||
// ======== User Info ========
|
||||
loadUserInfo() {
|
||||
// Try to get from globalData or storage
|
||||
const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo');
|
||||
if (userInfo && userInfo.name) {
|
||||
this.setData({
|
||||
userName: userInfo.name || '植物爱好者',
|
||||
userAvatar: userInfo.avatarUrl || userInfo.avatar || ''
|
||||
});
|
||||
return; // Use cached data, no API call
|
||||
}
|
||||
|
||||
// Only fetch from backend if no cached info
|
||||
request.get('/user/info').then(user => {
|
||||
if (!user) return;
|
||||
const avatarUrl = user.avatar ? user.avatar.url : '';
|
||||
this.setData({
|
||||
userName: user.name || '植物爱好者',
|
||||
userAvatar: avatarUrl
|
||||
});
|
||||
const info = {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
avatarUrl: avatarUrl,
|
||||
account: user.account,
|
||||
phone: user.phone,
|
||||
avatarId: user.avatarId
|
||||
};
|
||||
app.globalData.userInfo = info;
|
||||
wx.setStorageSync('userInfo', info);
|
||||
}).catch(() => { });
|
||||
},
|
||||
|
||||
// ======== Stats ========
|
||||
loadStats() {
|
||||
// Fetch plant count
|
||||
request.post('/plant/page', { current: 1, pageSize: 1 }).then(res => {
|
||||
this.setData({ plantCount: res.total || 0 });
|
||||
}).catch(() => { });
|
||||
|
||||
// Fetch post count - user's own posts
|
||||
request.post('/post/page', { current: 1, pageSize: 1, onlyMine: true }).then(res => {
|
||||
this.setData({ postCount: res.total || 0 });
|
||||
}).catch(() => { });
|
||||
|
||||
// Fetch completed tasks count
|
||||
request.get('/plant/taskCount').then(res => {
|
||||
this.setData({ taskDoneCount: res || 0 });
|
||||
}).catch(() => { });
|
||||
},
|
||||
|
||||
// ======== Navigation ========
|
||||
setView(e) {
|
||||
const view = e.currentTarget.dataset.view;
|
||||
this.setData({ view });
|
||||
|
||||
if (view === 'favorites') {
|
||||
this.loadFavorites();
|
||||
} else if (view === 'posts') {
|
||||
this.loadMyPosts();
|
||||
this.loadDrafts();
|
||||
}
|
||||
},
|
||||
|
||||
goBack() {
|
||||
this.setData({ view: 'profile' });
|
||||
},
|
||||
|
||||
// ======== Favorites ========
|
||||
loadFavorites() {
|
||||
// TODO: Call favorites API when available
|
||||
// request.get('/user/favorites').then(...)
|
||||
this.filterFavorites();
|
||||
},
|
||||
|
||||
onFavTabChange(e) {
|
||||
this.setData({ favTab: e.detail.value }, () => {
|
||||
this.filterFavorites();
|
||||
});
|
||||
},
|
||||
|
||||
filterFavorites() {
|
||||
const { favorites, favTab } = this.data;
|
||||
const filtered = favorites.filter(item => {
|
||||
if (favTab === 'all') return true;
|
||||
return item.type === favTab;
|
||||
});
|
||||
this.setData({ filteredFavorites: filtered });
|
||||
},
|
||||
|
||||
// ======== Posts ========
|
||||
loadMyPosts() {
|
||||
// Get published posts by current user
|
||||
const myPosts = MOCK_POSTS.filter(p => p.user === '我的花园');
|
||||
this.setData({ myPublishedPosts: myPosts });
|
||||
request.post('/post/page', { current: 1, pageSize: 50, onlyMine: true }).then(res => {
|
||||
const records = res.records || res.list || [];
|
||||
const posts = records.map(item => {
|
||||
const publisher = item.publisher || {};
|
||||
const imgList = item.imgList || [];
|
||||
return {
|
||||
id: item.id,
|
||||
content: item.content || '',
|
||||
time: this._formatTime(item.createdAt || item.createTime),
|
||||
images: imgList.map(img => img.url),
|
||||
likes: item.likeList || [],
|
||||
comments: item.commentList || []
|
||||
};
|
||||
});
|
||||
this.setData({ myPublishedPosts: posts });
|
||||
}).catch(() => {
|
||||
this.setData({ myPublishedPosts: [] });
|
||||
});
|
||||
},
|
||||
|
||||
loadDrafts() {
|
||||
// Load drafts from storage
|
||||
try {
|
||||
const draft = wx.getStorageSync('post_draft');
|
||||
if (draft && (draft.content || (draft.images && draft.images.length > 0))) {
|
||||
// Convert single draft to array for consistency
|
||||
this.setData({
|
||||
myDrafts: [{
|
||||
id: 'draft_1',
|
||||
@@ -63,39 +174,10 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
setView(e) {
|
||||
const view = e.currentTarget.dataset.view;
|
||||
this.setData({ view });
|
||||
|
||||
// Refresh data when entering posts view
|
||||
if (view === 'posts') {
|
||||
this.loadMyPosts();
|
||||
this.loadDrafts();
|
||||
}
|
||||
},
|
||||
|
||||
onFavTabChange(e) {
|
||||
const tab = e.detail.value;
|
||||
this.setData({ favTab: tab }, () => {
|
||||
this.filterFavorites();
|
||||
});
|
||||
},
|
||||
|
||||
onPostsTabChange(e) {
|
||||
const tab = e.detail.value;
|
||||
this.setData({ postsTab: tab });
|
||||
this.setData({ postsTab: e.detail.value });
|
||||
},
|
||||
|
||||
filterFavorites() {
|
||||
const { favorites, favTab } = this.data;
|
||||
const filtered = favorites.filter(item => {
|
||||
if (favTab === 'all') return true;
|
||||
return item.type === favTab;
|
||||
});
|
||||
this.setData({ filteredFavorites: filtered });
|
||||
},
|
||||
|
||||
// Delete a published post
|
||||
deletePost(e) {
|
||||
const postId = e.currentTarget.dataset.id;
|
||||
wx.showModal({
|
||||
@@ -103,42 +185,176 @@ Page({
|
||||
content: '确定要删除这条动态吗?',
|
||||
confirmColor: '#EF5350',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// Remove from MOCK_POSTS
|
||||
const idx = MOCK_POSTS.findIndex(p => p.id === postId);
|
||||
if (idx > -1) {
|
||||
MOCK_POSTS.splice(idx, 1);
|
||||
}
|
||||
if (!res.confirm) return;
|
||||
wx.showLoading({ title: '删除中...' });
|
||||
request.get('/post/delete', { id: postId }).then(() => {
|
||||
wx.hideLoading();
|
||||
this.loadMyPosts();
|
||||
wx.showToast({ title: '已删除', icon: 'success' });
|
||||
}
|
||||
}).catch(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({ title: '删除失败', icon: 'none' });
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Edit a draft
|
||||
editDraft(e) {
|
||||
// Navigate to create page, which will load the draft
|
||||
wx.navigateTo({
|
||||
url: '/pages/community/create/index'
|
||||
});
|
||||
editDraft() {
|
||||
wx.navigateTo({ url: '/pages/community/create/index' });
|
||||
},
|
||||
|
||||
// Delete a draft
|
||||
deleteDraft(e) {
|
||||
deleteDraft() {
|
||||
wx.showModal({
|
||||
title: '删除草稿',
|
||||
content: '确定要删除这份草稿吗?',
|
||||
confirmColor: '#EF5350',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
wx.removeStorageSync('post_draft');
|
||||
} catch (e) { }
|
||||
this.setData({ myDrafts: [] });
|
||||
wx.showToast({ title: '已删除', icon: 'success' });
|
||||
}
|
||||
if (!res.confirm) return;
|
||||
try { wx.removeStorageSync('post_draft'); } catch (e) { }
|
||||
this.setData({ myDrafts: [] });
|
||||
wx.showToast({ title: '已删除', icon: 'success' });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// ======== Menu Actions ========
|
||||
goToIdentifyHistory() {
|
||||
wx.navigateTo({ url: '/pages/profile/identify-history/index' });
|
||||
},
|
||||
|
||||
goToNotificationSettings() {
|
||||
// Open WeChat notification settings
|
||||
wx.openSetting({
|
||||
success: (res) => {
|
||||
console.log('Settings opened', res);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
goToAbout() {
|
||||
this.setData({ view: 'about' });
|
||||
},
|
||||
|
||||
goToAgreement() {
|
||||
// TODO: Navigate to agreement page or show inline
|
||||
wx.showToast({ title: '功能开发中', icon: 'none' });
|
||||
},
|
||||
|
||||
goToPrivacy() {
|
||||
// TODO: Navigate to privacy page or show inline
|
||||
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 } = this.data;
|
||||
|
||||
if (!tempAvatar && !tempNickname) {
|
||||
wx.showToast({ title: '请选择头像或输入昵称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
wx.showLoading({ title: '保存中...', mask: true });
|
||||
|
||||
try {
|
||||
const updatePayload = {};
|
||||
|
||||
// 1. Upload avatar if changed
|
||||
if (tempAvatar) {
|
||||
const data = await request.upload(tempAvatar);
|
||||
const fileData = data?.file || {};
|
||||
if (fileData.id) {
|
||||
updatePayload.avatar_id = fileData.id;
|
||||
// Update local display
|
||||
this.setData({ userAvatar: fileData.url || tempAvatar });
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Set name if provided
|
||||
if (tempNickname) {
|
||||
updatePayload.name = tempNickname;
|
||||
this.setData({ userName: tempNickname });
|
||||
}
|
||||
|
||||
// 3. Call update API
|
||||
if (Object.keys(updatePayload).length > 0) {
|
||||
await request.post('/user/update', updatePayload);
|
||||
}
|
||||
|
||||
wx.hideLoading();
|
||||
this.setData({ showProfileEditor: false });
|
||||
wx.showToast({ title: '资料已更新', icon: 'success' });
|
||||
|
||||
// Update globalData
|
||||
const userInfo = app.globalData.userInfo || {};
|
||||
if (updatePayload.name) userInfo.name = updatePayload.name;
|
||||
if (updatePayload.avatar_id) userInfo.avatarId = updatePayload.avatar_id;
|
||||
app.globalData.userInfo = userInfo;
|
||||
} catch (err) {
|
||||
wx.hideLoading();
|
||||
console.error('Save profile failed', err);
|
||||
wx.showToast({ title: '保存失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
// ======== 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(...) },
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user