199 lines
5.4 KiB
TypeScript
199 lines
5.4 KiB
TypeScript
import { CATEGORY_LIST_WITH_ALL } from '../../core/data/categories';
|
|
import { CATEGORY_DATA, type CategoryItem } from './category.data';
|
|
|
|
type CategoryTab = {
|
|
id: string;
|
|
name: string;
|
|
icon: string;
|
|
};
|
|
|
|
type CategoryDataset = {
|
|
searchPlaceholder: string;
|
|
categories: Array<{
|
|
id: string;
|
|
name: string;
|
|
icon: string;
|
|
items: CategoryItem[];
|
|
}>;
|
|
};
|
|
|
|
const SIDEBAR_TABS: CategoryTab[] = CATEGORY_LIST_WITH_ALL.map(
|
|
({ id, name, icon }) => ({
|
|
id,
|
|
name,
|
|
icon,
|
|
}),
|
|
);
|
|
|
|
const TAB_BAR_PATHS = new Set([
|
|
'/pages/home/home',
|
|
'/pages/category/category',
|
|
'/pages/age/age',
|
|
'/pages/favorites/favorites',
|
|
'/pages/profile/profile',
|
|
]);
|
|
|
|
// Page-level mutable state (shared across methods, set once on load)
|
|
let _categoryData: CategoryDataset | null = null;
|
|
|
|
function buildAllItems(): CategoryItem[] {
|
|
if (!_categoryData) return [];
|
|
const items: CategoryItem[] = [];
|
|
for (const group of _categoryData.categories) {
|
|
for (const item of group.items) {
|
|
items.push({ ...item });
|
|
}
|
|
}
|
|
return items;
|
|
}
|
|
|
|
function getItemsByCategory(categoryId: string): CategoryItem[] {
|
|
if (!_categoryData) return [];
|
|
if (categoryId === 'all') return buildAllItems();
|
|
const group = _categoryData.categories.find((c) => c.id === categoryId);
|
|
if (!group) return [];
|
|
return group.items.map((item) => ({ ...item }));
|
|
}
|
|
|
|
function filterByKeyword(
|
|
items: CategoryItem[],
|
|
keyword: string,
|
|
): CategoryItem[] {
|
|
if (!keyword) return items;
|
|
const kw = keyword.toLowerCase();
|
|
return items.filter(
|
|
(item) =>
|
|
item.title.toLowerCase().includes(kw) ||
|
|
item.subtitle.toLowerCase().includes(kw),
|
|
);
|
|
}
|
|
|
|
// Skeleton placeholder items for loading state
|
|
const SKELETON_ITEMS = Array.from({ length: 4 }, (_, i) => ({
|
|
id: `skeleton-${i}`,
|
|
title: '\u00A0',
|
|
subtitle: '\u00A0',
|
|
skeleton: true,
|
|
}));
|
|
|
|
Page({
|
|
data: {
|
|
searchPlaceholder: '搜索练习纸...',
|
|
searchKeyword: '',
|
|
sidebarTabs: SIDEBAR_TABS,
|
|
activeCategoryId: 'all',
|
|
displayItems: SKELETON_ITEMS as any[],
|
|
scrollIntoViewId: '',
|
|
loading: true,
|
|
},
|
|
|
|
onLoad(options: Record<string, string>) {
|
|
void this.initData(options);
|
|
},
|
|
|
|
async initData(options: Record<string, string>) {
|
|
wx.showLoading({ title: '加载中', mask: false });
|
|
|
|
const app = getApp<IAppOption>();
|
|
const config = await app.getPageConfig();
|
|
|
|
// Use cloud config if available, otherwise fallback to local static data
|
|
if (config?.category?.categories?.length) {
|
|
_categoryData = {
|
|
searchPlaceholder:
|
|
config.category.searchPlaceholder || '搜索练习纸...',
|
|
categories: config.category.categories.map((cat) => ({
|
|
id: cat.id,
|
|
name: cat.name,
|
|
icon: cat.icon,
|
|
items: (cat.items || []).map(
|
|
(raw) => raw as unknown as CategoryItem,
|
|
),
|
|
})),
|
|
};
|
|
} else {
|
|
_categoryData = CATEGORY_DATA;
|
|
}
|
|
|
|
const activeId = options.id && options.id !== 'all' ? options.id : 'all';
|
|
const items = getItemsByCategory(activeId);
|
|
|
|
this.setData({
|
|
loading: false,
|
|
searchPlaceholder: _categoryData.searchPlaceholder,
|
|
activeCategoryId: activeId,
|
|
displayItems: items,
|
|
});
|
|
|
|
wx.hideLoading();
|
|
},
|
|
|
|
onTapCategory(e: WechatMiniprogram.TouchEvent) {
|
|
const id = e.currentTarget.dataset.id as string;
|
|
if (!id || id === this.data.activeCategoryId) return;
|
|
|
|
const items = getItemsByCategory(id);
|
|
const filtered = filterByKeyword(items, this.data.searchKeyword);
|
|
|
|
this.setData({
|
|
activeCategoryId: id,
|
|
displayItems: filtered,
|
|
scrollIntoViewId: '',
|
|
});
|
|
},
|
|
|
|
onSearchInput(e: WechatMiniprogram.Input) {
|
|
const keyword = (e.detail.value ?? '').trim();
|
|
const items = getItemsByCategory(this.data.activeCategoryId);
|
|
const filtered = filterByKeyword(items, keyword);
|
|
|
|
this.setData({
|
|
searchKeyword: keyword,
|
|
displayItems: filtered,
|
|
});
|
|
},
|
|
|
|
onClearSearch() {
|
|
const items = getItemsByCategory(this.data.activeCategoryId);
|
|
this.setData({
|
|
searchKeyword: '',
|
|
displayItems: items,
|
|
});
|
|
},
|
|
|
|
onTapItem(e: WechatMiniprogram.TouchEvent) {
|
|
const path = e.currentTarget.dataset.path as string;
|
|
const title = e.currentTarget.dataset.title as string;
|
|
const available = e.currentTarget.dataset.available;
|
|
|
|
if (!available || !path) {
|
|
wx.showToast({
|
|
title: title ? `${title} 即将上线` : '即将上线',
|
|
icon: 'none',
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (TAB_BAR_PATHS.has(path)) {
|
|
wx.switchTab({ url: path });
|
|
return;
|
|
}
|
|
|
|
wx.navigateTo({ url: path });
|
|
},
|
|
|
|
onShareAppMessage() {
|
|
return {
|
|
title: '涂鸦丫 - 全部练习分类',
|
|
path: '/pages/category/category',
|
|
};
|
|
},
|
|
|
|
onShareTimeline() {
|
|
return {
|
|
title: '涂鸦丫 - 全部练习分类',
|
|
query: '',
|
|
};
|
|
},
|
|
});
|