Files
fitness-coach/miniprogram/pages/detail/detail.js
wm 70ff806042 feat: 小程序连接服务器IP + 同步未提交开发
- miniprogram/config.js: BASE_URL 指向 http://192.227.237.8:3001
- 动作标题中文化(nameZh),搜索匹配 name/nameZh/nameEn
- 新增计划/收藏/我的 等页面与组件
- 后端 Docker 化(Dockerfile/.dockerignore)与翻译脚本
- .gitignore 补充 .DS_Store
2026-07-22 14:05:30 +08:00

139 lines
4.2 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 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 });
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) => {
// 详情页用 GIF 演示动作;记录当前图源以便失败时降级到 JPG / 占位
const heroSrc = ex && (ex.gifUrl || ex.image) ? (ex.gifUrl || ex.image) : '';
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' });
}
},
// 详情大图加载失败GIF→JPG→emoji 占位,三级降级保证不空白
onHeroError() {
const ex = this.data.exercise || {};
const showingGif = this.data.heroSrc && ex.gifUrl && this.data.heroSrc === ex.gifUrl;
if (showingGif && ex.image) {
this.setData({ heroSrc: ex.image });
} else {
this.setData({ heroError: true });
}
},
onExercise(e) {
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
};
}
});