const app = getApp(); const svc = require('../../services/exercise'); const DIM_MAP = { bodyPart: 'body-parts', equipment: 'equipment', target: 'targets', muscleGroup: 'muscle-groups', type: 'types' }; const SECONDARY_LABEL = { bodyPart: '部位', equipment: '器械' }; function labelForDim(d) { return ({ bodyPart: '按部位', equipment: '按器械', target: '按目标', muscleGroup: '按肌群', type: '按类型' })[d] || '分类'; } Page({ data: { statusBarHeight: 20, dimension: 'bodyPart', title: '分类', dimTitle: '分类', // 主维度支持多选:activeValues 为已选 value 数组(空数组 = 全部) activeValues: [], values: [], // 二级维度(多维度筛选):进入器械维度时交叉按部位,其余维度交叉按器械 secondaryDim: 'equipment', secondaryKey: 'equipment', secondaryLabel: '器械', secondaryList: [], secondarySelected: [], exercises: [], loading: true, loadingMore: false, hasMore: true, page: 1, pageSize: 20, total: 0 }, onLoad(query) { const dimension = query.dimension || 'bodyPart'; const value = query.value || ''; const activeValues = value ? [value] : []; const secondaryDim = dimension === 'equipment' ? 'bodyPart' : 'equipment'; const title = query.title || labelForDim(dimension); this.setData({ statusBarHeight: app.globalData.statusBarHeight || 20, dimension, activeValues, dimTitle: labelForDim(dimension), secondaryDim, secondaryKey: DIM_MAP[secondaryDim] || 'equipment', secondaryLabel: SECONDARY_LABEL[secondaryDim] || '器械', title }); this.loadValues(); }, loadValues() { this.setData({ loading: true }); const key = DIM_MAP[this.data.dimension] || 'body-parts'; const secKey = this.data.secondaryKey; Promise.all([ svc.getCategories(key), svc.getCategories(secKey).catch(() => []) ]).then(([items, secItems]) => { const list = (items || []).slice(); // 头部插入「全部」项:明确当前为「全部」 list.unshift({ value: '', label: '全部' }); // 用分类枚举里的干净中文标签回写标题,避免外部传入的标题出现乱码 let title = this.data.title; const { activeValues } = this.data; if (activeValues.length === 1) { const hit = list.find((it) => it.value === activeValues[0]); if (hit && hit.label) title = hit.label; } else if (activeValues.length > 1) { title = `已选 ${activeValues.length} 个`; } // 主维度 items 带 active 标志(供 filter-bar 置顶/内联展示) const primaryItems = list.map((it) => ({ ...it, active: activeValues.includes(it.value) })); const secList = (secItems || []).slice().map((it) => ({ ...it, active: this.data.secondarySelected.includes(it.value) })); this.setData({ values: primaryItems, secondaryList: secList, title, loading: false }); this.loadExercises(); }).catch(() => { this.setData({ loading: false }); }); }, buildParams(page) { const params = { page, pageSize: this.data.pageSize }; const av = this.data.activeValues; if (av.length) params[this.data.dimension] = av.join(','); if (this.data.secondarySelected.length) { params[this.data.secondaryDim] = this.data.secondarySelected.join(','); } return params; }, loadExercises() { this.setData({ loading: true, page: 1 }); svc.listExercises(this.buildParams(1)).then((res) => { const items = (res && res.items) || []; const total = (res && res.total) || 0; this.setData({ exercises: items, total, loading: false, hasMore: items.length < total }); }).catch(() => { this.setData({ loading: false }); }); }, onReachBottom() { if (this.data.loading || this.data.loadingMore || !this.data.hasMore) return; this.loadMore(); }, loadMore() { const next = this.data.page + 1; this.setData({ loadingMore: true }); svc.listExercises(this.buildParams(next)).then((res) => { const items = (res && res.items) || []; const total = (res && res.total) || 0; const merged = this.data.exercises.concat(items); this.setData({ exercises: merged, total, page: next, loadingMore: false, hasMore: merged.length < total }); }).catch(() => { this.setData({ loadingMore: false }); }); }, // 主维度(按器械/按部位)多选 onPrimaryChange(e) { const vals = e.detail.values || []; const values = this.data.values.map((it) => ({ ...it, active: vals.includes(it.value) })); let title = this.data.title; if (vals.length === 1) { const hit = values.find((it) => it.value === vals[0]); title = (hit && hit.label) || labelForDim(this.data.dimension); } else if (vals.length > 1) { title = `已选 ${vals.length} 个`; } else { title = labelForDim(this.data.dimension); } this.setData({ activeValues: vals, values, title, page: 1 }, () => this.loadExercises()); }, // 二级维度(部位/器械)多选 onSecondaryChange(e) { const values = e.detail.values || []; const secondaryList = this.data.secondaryList.map((it) => ({ ...it, active: values.includes(it.value) })); this.setData({ secondarySelected: values, secondaryList, page: 1 }, () => this.loadExercises()); }, onSecondaryClear() { const secondaryList = this.data.secondaryList.map((it) => ({ ...it, active: false })); this.setData({ secondarySelected: [], secondaryList, page: 1 }, () => this.loadExercises()); }, onExercise(e) { if (!e || !e.detail || !e.detail.id) return; wx.navigateTo({ url: '/pages/detail/detail?id=' + encodeURIComponent(e.detail.id) }); } });