203 lines
5.8 KiB
JavaScript
203 lines
5.8 KiB
JavaScript
// pages/wiki/index.js
|
|
import request from '../../utils/request';
|
|
|
|
Page({
|
|
data: {
|
|
// Categories
|
|
categories: [],
|
|
activeCategory: 'all', // 'all' or category id
|
|
|
|
// Display Data
|
|
displayedList: [],
|
|
|
|
// Filter State
|
|
searchQuery: '',
|
|
|
|
// Pagination State
|
|
current: 1,
|
|
pageSize: 10,
|
|
isLoading: false,
|
|
hasMore: true,
|
|
|
|
// Modal State
|
|
showIdentifyModal: false
|
|
},
|
|
|
|
onLoad() {
|
|
this.fetchCategories();
|
|
this.fetchWikiList(true);
|
|
},
|
|
|
|
onShow() {
|
|
if (typeof this.getTabBar === 'function' &&
|
|
this.getTabBar()) {
|
|
this.getTabBar().setData({ selected: 3 });
|
|
}
|
|
},
|
|
|
|
// Fetch categories from API
|
|
fetchCategories() {
|
|
request.get('/wiki-class/list').then(res => {
|
|
const list = (res && res.list) || (Array.isArray(res) ? res : []);
|
|
this.setData({ categories: list });
|
|
}).catch(err => {
|
|
console.error('Fetch categories failed', err);
|
|
});
|
|
},
|
|
|
|
// Fetch wiki list from API
|
|
fetchWikiList(reset = false) {
|
|
if (this.data.isLoading) return;
|
|
if (!reset && !this.data.hasMore) return;
|
|
|
|
const current = reset ? 1 : this.data.current;
|
|
|
|
this.setData({ isLoading: true });
|
|
|
|
// Build params
|
|
const params = {
|
|
current: current,
|
|
pageSize: this.data.pageSize
|
|
};
|
|
|
|
// Search query
|
|
if (this.data.searchQuery) {
|
|
params.name = this.data.searchQuery;
|
|
}
|
|
|
|
// Category filter
|
|
if (this.data.activeCategory !== 'all') {
|
|
params.classId = [this.data.activeCategory];
|
|
}
|
|
|
|
request.post('/wiki/page', params).then(res => {
|
|
const data = res || {};
|
|
const list = data.list || [];
|
|
const total = data.total || 0;
|
|
|
|
// Map API data to display model
|
|
const mappedList = list.map(item => ({
|
|
id: item.id,
|
|
name: item.name,
|
|
latinName: item.latinName || '',
|
|
aliases: item.aliases || '',
|
|
genus: item.genus || '',
|
|
difficulty: item.difficulty || 0,
|
|
isHot: item.isHot === 1,
|
|
image: (item.imgList && item.imgList.length > 0) ? item.imgList[0].url : '',
|
|
classes: (item.classes || []).map(c => c.name),
|
|
// Pass the full item for detail navigation
|
|
raw: item
|
|
}));
|
|
|
|
if (reset) {
|
|
this.setData({
|
|
displayedList: mappedList,
|
|
current: 2,
|
|
hasMore: mappedList.length < total,
|
|
isLoading: false
|
|
});
|
|
} else {
|
|
// Append using data path for performance
|
|
const updateData = {};
|
|
const currentLen = this.data.displayedList.length;
|
|
mappedList.forEach((item, index) => {
|
|
updateData[`displayedList[${currentLen + index}]`] = item;
|
|
});
|
|
updateData['current'] = current + 1;
|
|
updateData['hasMore'] = (currentLen + mappedList.length) < total;
|
|
updateData['isLoading'] = false;
|
|
this.setData(updateData);
|
|
}
|
|
}).catch(err => {
|
|
console.error('Fetch wiki list failed', err);
|
|
this.setData({ isLoading: false });
|
|
});
|
|
},
|
|
|
|
// Search Input Handler (debounced)
|
|
onSearchInput(e) {
|
|
const value = e.detail.value;
|
|
this.setData({ searchQuery: value });
|
|
|
|
// Debounce search
|
|
if (this._searchTimer) clearTimeout(this._searchTimer);
|
|
this._searchTimer = setTimeout(() => {
|
|
this.fetchWikiList(true);
|
|
}, 500);
|
|
},
|
|
|
|
// Category Filter Handler
|
|
setCategory(e) {
|
|
const catId = e.currentTarget.dataset.cat;
|
|
this.setData({ activeCategory: catId }, () => {
|
|
this.fetchWikiList(true);
|
|
});
|
|
},
|
|
|
|
// Infinite Scroll Handler
|
|
onReachBottom() {
|
|
this.fetchWikiList(false);
|
|
},
|
|
|
|
// Pull down refresh
|
|
onPullDownRefresh() {
|
|
this.fetchCategories();
|
|
this.fetchWikiList(true);
|
|
wx.stopPullDownRefresh();
|
|
},
|
|
|
|
goToDetail(e) {
|
|
const item = e.currentTarget.dataset.item;
|
|
wx.navigateTo({
|
|
url: `/pages/wiki/detail/index?id=${item.id}`
|
|
});
|
|
},
|
|
|
|
// Difficulty label helper
|
|
getDifficultyLabel(level) {
|
|
const labels = { 1: '简单', 2: '中等', 3: '较难', 4: '困难', 5: '专家' };
|
|
return labels[level] || '未知';
|
|
},
|
|
|
|
openIdentifyModal() { this.setData({ showIdentifyModal: true }); },
|
|
|
|
onPopupVisibleChange(e) {
|
|
this.setData({
|
|
showIdentifyModal: e.detail.visible
|
|
});
|
|
},
|
|
|
|
closeIdentifyModal() { this.setData({ showIdentifyModal: false }); },
|
|
|
|
// Handle plant identification: camera or album
|
|
handleIdentify(e) {
|
|
const source = e.currentTarget.dataset.source; // 'camera' or 'album'
|
|
|
|
wx.chooseMedia({
|
|
count: 1,
|
|
mediaType: ['image'],
|
|
sourceType: [source],
|
|
camera: 'back',
|
|
success: (res) => {
|
|
const tempFilePath = res.tempFiles[0].tempFilePath;
|
|
|
|
// Close popup
|
|
this.setData({ showIdentifyModal: false });
|
|
|
|
// Store image path in global data for the results page
|
|
const app = getApp();
|
|
app.globalData._identifyImagePath = tempFilePath;
|
|
|
|
// Navigate to identify results page
|
|
wx.navigateTo({
|
|
url: '/pages/wiki/identify/index'
|
|
});
|
|
},
|
|
fail: () => {
|
|
// User cancelled, do nothing
|
|
}
|
|
});
|
|
}
|
|
})
|