Files
wm ff3a120b55 feat(plan): 新增「加入计划」选择器页 + 增强官方计划浏览,修复返回不刷新
1) 新增 pages/plan-select(加入我的计划选择器,替换详情页 actionSheet)
   - 默认展示我全部计划(浏览,不再强制搜索),支持 最近创建/动作最多 排序 + 名称搜索
   - 点选即把动作加入该计划并返回;无计划时引导新建
   - 入口接在 detail 页「加入计划」(无 planId 时 navigate 至此)
2) 增强 pages/collection(官方训练计划)
   - 默认展示全部分级,新增 等级筛选 chips + 名称搜索(均用现有字段,不改后端)
   - 筛选/搜索纯前端,viewGroups 驱动渲染
3) 修复 plan-detail 从「添加动作」返回后列表不刷新(上轮已单独提交 7ff55a6)
4) app.json 注册 plan-select 页面
2026-07-23 14:15:41 +08:00

136 lines
4.1 KiB
JavaScript
Raw Permalink 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 svc = require('../../services/exercise');
const favSvc = require('../../services/favorite');
const planSvc = require('../../services/plan');
const auth = require('../../utils/auth');
Page({
data: {
statusBarHeight: 20,
id: '',
planId: '',
exercise: null,
heroSrc: '',
heroGif: '',
heroError: false,
related: [],
loading: true,
favorited: false
},
onLoad(query) {
const id = query.id || '';
const planId = query.planId || '';
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 20, id, planId });
// 防御id 缺失直接显示空态,避免请求 /api/exercises/ 导致错乱或 404
if (!id) {
this.setData({ loading: false });
return;
}
this.load();
if (auth.isLogin()) {
favSvc.exerciseStatus(id).then((r) => {
this.setData({ favorited: !!(r && r.favorited) });
}).catch(() => {});
}
},
load() {
this.setData({ loading: true });
svc.getExercise(this.data.id).then((ex) => {
// 海报用超分 JPG(720px 清晰);动图用原始 GIF由 gif-player 组件逐帧播放
const heroSrc = ex && (ex.image || ex.gifUrl) ? (ex.image || ex.gifUrl) : '';
const heroGif = ex && ex.gifUrl ? ex.gifUrl : '';
this.setData({ exercise: ex, heroSrc, heroGif, heroError: false, loading: false });
if (ex && ex.target) {
svc.listExercises({ target: ex.target, pageSize: 6 }).then((res) => {
const related = ((res && res.items) || [])
.filter(i => i.id !== ex.id)
.slice(0, 6);
this.setData({ related });
}).catch(() => {});
}
}).catch(() => {
this.setData({ loading: false });
});
},
// 收藏 / 取消收藏(心形按钮)
onToggleFav() {
auth.ensureLogin().then(() => {
const id = this.data.id;
const wasFav = this.data.favorited;
const op = wasFav ? favSvc.removeExercise(id) : favSvc.addExercise(id);
op.then(() => {
this.setData({ favorited: !wasFav });
wx.showToast({ title: wasFav ? '已取消收藏' : '已收藏', icon: 'none' });
}).catch(() => {});
}).catch(() => {});
},
// 底部主按钮:加入计划
// - 若从某计划内进入(带 planId直接加入该计划
// - 否则进入「加入计划」选择器页,可浏览全部计划并筛选
onAdd() {
if (this.data.planId) {
planSvc.addExercise(this.data.planId, this.data.id).then(() => {
wx.showToast({ title: '已加入计划', icon: 'success' });
setTimeout(() => wx.navigateBack(), 500);
}).catch(() => {});
return;
}
auth.ensureLogin().then(() => {
const name = this.data.exercise
? (this.data.exercise.displayName || this.data.exercise.name)
: '';
wx.navigateTo({
url: '/pages/plan-select/plan-select?exerciseId=' + encodeURIComponent(this.data.id) +
'&name=' + encodeURIComponent(name || '')
});
}).catch(() => {});
},
onBack() {
const pages = getCurrentPages();
if (pages.length > 1) {
wx.navigateBack();
} else {
wx.reLaunch({ url: '/pages/index/index' });
}
},
// 详情大图加载失败JPG↔GIF 互为降级,最后 emoji 占位,保证不空白
onHeroError() {
const ex = this.data.exercise || {};
const cur = this.data.heroSrc;
if (cur === ex.image && ex.gifUrl) {
this.setData({ heroSrc: ex.gifUrl });
} else if (cur === ex.gifUrl && ex.image) {
this.setData({ heroSrc: ex.image });
} else {
this.setData({ heroError: true });
}
},
onExercise(e) {
if (!e || !e.detail || !e.detail.id) return;
wx.navigateTo({ url: '/pages/detail/detail?id=' + encodeURIComponent(e.detail.id) });
},
onShareAppMessage() {
const ex = this.data.exercise || {};
const name = ex.displayName || ex.name || '';
return {
title: name ? ('FITCOACH · ' + name) : 'FITCOACH 智能健身教练',
path: '/pages/detail/detail?id=' + this.data.id
};
},
onShareTimeline() {
return {
title: 'FITCOACH · 精准训练推荐',
query: 'id=' + this.data.id
};
}
});