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: '', 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 / 占位 const heroSrc = ex && (ex.image || ex.gifUrl) ? (ex.image || ex.gifUrl) : ''; this.setData({ exercise: ex, heroSrc, 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(() => {}); }, // 底部主按钮:加入计划(真实选择器) 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(() => planSvc.listMine()).then((res) => { const plans = (res && res.items) || res || []; if (!plans.length) { wx.showModal({ title: '还没有训练计划', content: '先创建一个计划,再把动作加进去吧~', confirmText: '去创建', cancelText: '稍后', success: (r) => { if (r.confirm) wx.navigateTo({ url: '/pages/plan-edit/plan-edit' }); } }); return; } const names = plans.slice(0, 6).map((p) => p.name); wx.showActionSheet({ itemList: names, success: (sheet) => { const plan = plans[sheet.tapIndex]; if (!plan) return; planSvc.addExercise(plan.id, this.data.id).then(() => { wx.showToast({ title: '已加入「' + plan.name + '」', icon: 'success' }); }).catch(() => {}); } }); }).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 }; } });