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