Files

191 lines
5.9 KiB
JavaScript
Raw Permalink 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 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) });
}
});