- detail 顶部 favbtn 浮窗(需避让胶囊、丑)移除,改为底部 addbar 内与 CTA 并排的方形按钮 - fc-icon 新增 filled 属性:收藏态实心心形(Lucide 描边图标默认 fill=none,filled=true 时 fill=stroke 变实心) - 收藏按钮美化:圆角 24rpx 方形 + 发丝边框,未收藏描边(text-2)、已收藏实心(accent)+ accent-soft 底色 + accent-ring 边框 + 点按 scale 反馈 - detail.js 清理 favRight/favTop 胶囊避让逻辑(不再需要)
149 lines
4.6 KiB
JavaScript
149 lines
4.6 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(() => {});
|
||
},
|
||
|
||
// 底部主按钮:加入计划(真实选择器)
|
||
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
|
||
};
|
||
}
|
||
});
|