Files
fitness-coach/miniprogram/pages/recommend/recommend.js
wm b3b58e66fb feat: init fitness-coach (backend + miniprogram)
- backend: NestJS service with exercise/plan data
- miniprogram: WeChat mini program client
- exclude node_modules, dist, runtime data-store, local env
2026-07-22 00:35:40 +08:00

92 lines
2.6 KiB
JavaScript

const app = getApp();
const svc = require('../../services/exercise');
Page({
data: {
statusBarHeight: 20,
step: 1, // 1: 选择目标肌群 / 2: 展示结果
bodyGroups: [],
selectedTarget: '',
selectedTargetLabel: '',
equipments: [],
selectedEquipment: '',
results: [],
loading: false
},
onLoad() {
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 20 });
this.prepare();
},
prepare() {
this.setData({ loading: true });
Promise.all([
svc.getCategories('targets').catch(() => []),
svc.getCategories('equipment').catch(() => []),
svc.getCategories('body-parts').catch(() => [])
]).then(([targets, equipments, bodyParts]) => {
const tList = targets || [];
// 按 bodyPart 将目标肌群分组展示;后端未返回分组字段时退化为单组
const grouped = {};
(bodyParts || []).forEach(bp => { grouped[bp.value] = { label: bp.label, targets: [] }; });
tList.forEach(t => {
const key = t.bodyPart || 'other';
if (!grouped[key]) grouped[key] = { label: t.bodyPartLabel || '其他', targets: [] };
grouped[key].targets.push(t);
});
const bodyGroups = Object.keys(grouped)
.map(k => grouped[k])
.filter(g => g.targets.length);
this.setData({
bodyGroups: bodyGroups.length ? bodyGroups : [{ label: '全部目标肌群', targets: tList }],
equipments: equipments || [],
loading: false
});
}).catch(() => {
this.setData({ loading: false });
});
},
onSelectTarget(e) {
this.setData({
selectedTarget: e.currentTarget.dataset.value,
selectedTargetLabel: e.currentTarget.dataset.label
});
},
onSelectEquipment(e) {
const value = e.currentTarget.dataset.value;
this.setData({ selectedEquipment: this.data.selectedEquipment === value ? '' : value });
},
onConfirm() {
if (!this.data.selectedTarget) {
wx.showToast({ title: '请先选择目标肌群', icon: 'none' });
return;
}
this.setData({ loading: true, step: 2 });
svc.recommend({
target: this.data.selectedTarget,
equipment: this.data.selectedEquipment,
limit: 20
}).then((res) => {
this.setData({ results: (res && res.items) || [], loading: false });
}).catch(() => {
this.setData({ loading: false });
});
},
onBack() {
if (this.data.step === 2) {
this.setData({ step: 1 });
} else {
wx.navigateBack();
}
},
onExercise(e) {
wx.navigateTo({ url: '/pages/detail/detail?id=' + encodeURIComponent(e.detail.id) });
}
});