Files
fitness-coach/miniprogram/pages/profile/profile.js
wm 4dba91a16e fix: 首页我的计划点击跳转错页 + feat: 新增留言反馈功能
fix:
- 首页'我的计划'卡片误绑 onExercise(跳动作详情),改为 onPlanTap 正确跳训练计划详情页
- 修复后点击计划可正常打开 plan-detail

feat(留言反馈):
- 后端新增 feedback 模块:POST /api/feedback(AuthGuard,content 必填/contact 选填),JsonStore 持久化
- 前端新增 pages/feedback 页面(留言内容 textarea + 联系方式选填 + 提交),profile 菜单新增'意见反馈'入口
- icon-svg 新增 message-circle 图标(反馈页用)
2026-07-22 23:21:18 +08:00

133 lines
3.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const app = getApp();
const auth = require('../../utils/auth');
const favSvc = require('../../services/favorite');
const planSvc = require('../../services/plan');
// UGC 头像图标选择器Lucide 运动子集(非 emoji
const ICONS = ['dumbbell', 'accessibility', 'person-standing', 'bike', 'heart', 'flame',
'target', 'medal', 'trophy', 'award', 'star', 'activity', 'sparkles', 'zap', 'trending-up'];
Page({
data: {
statusBarHeight: 20,
loggedIn: false,
profile: { nickname: '', avatar: 'user' },
counts: { fav: 0, plans: 0, favPlans: 0 },
loading: false,
// 编辑态
showEmojiPicker: false,
emojis: ICONS,
draftNickname: '',
draftAvatar: 'user'
},
onLoad() {
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 20 });
},
onShow() {
this.loadData();
},
loadData() {
if (!auth.isLogin()) {
this.setData({ loggedIn: false });
return;
}
const profile = auth.getProfile();
this.setData({ loggedIn: true, profile, loading: true });
Promise.all([
favSvc.listExercises().catch(() => []),
planSvc.listMine().catch(() => []),
favSvc.listPlans().catch(() => [])
]).then(([fav, plans, favPlans]) => {
this.setData({
counts: {
fav: (fav || []).length,
plans: (plans || []).length,
favPlans: (favPlans || []).length
},
loading: false
});
}).catch(() => {
this.setData({ loading: false });
});
},
onLogin() {
auth.login().then(() => {
this.loadData();
wx.showToast({ title: '登录成功', icon: 'success' });
}).catch(() => {});
},
onEdit() {
const cur = this.data.profile;
wx.showModal({
title: '修改昵称',
editable: true,
placeholderText: '输入昵称',
content: cur.nickname || '',
success: (res) => {
if (res.confirm) {
this.setData({
draftNickname: (res.content || '').trim() || cur.nickname,
draftAvatar: cur.avatar || 'user',
showEmojiPicker: true
});
}
}
});
},
onPickEmoji(e) {
this.setData({ draftAvatar: e.currentTarget.dataset.emoji });
},
onCancelEdit() {
this.setData({ showEmojiPicker: false });
},
onConfirmEdit() {
const nickname = (this.data.draftNickname || '').trim();
const avatar = this.data.draftAvatar;
if (!nickname) {
wx.showToast({ title: '昵称不能为空', icon: 'none' });
return;
}
wx.showLoading({ title: '保存中…', mask: true });
auth.updateProfile({ nickname, avatar }).then((p) => {
wx.hideLoading();
this.setData({ profile: p, showEmojiPicker: false });
wx.showToast({ title: '已保存', icon: 'success' });
}).catch(() => {
wx.hideLoading();
});
},
onLogout() {
wx.showModal({
title: '退出登录',
content: '确定要退出当前账号吗?',
success: (res) => {
if (res.confirm) {
auth.logout();
this.setData({
loggedIn: false,
profile: { nickname: '', avatar: 'user' },
counts: { fav: 0, plans: 0, favPlans: 0 }
});
}
}
});
},
goFav() { wx.navigateTo({ url: '/pages/favorites/favorites' }); },
goPlans() { wx.navigateTo({ url: '/pages/my-plans/my-plans' }); },
goFavPlans() { wx.navigateTo({ url: '/pages/plan-favorites/plan-favorites' }); },
goOfficial() { wx.navigateTo({ url: '/pages/collection/collection' }); },
goFeedback() { wx.navigateTo({ url: '/pages/feedback/feedback' }); },
noop() {}
});