// components/journal-list/index.ts import config from "../../config/index"; import { JournalPage, JournalPageType } from "../../types/Journal"; import { OrderType } from "../../types/Model"; import Time from "../../utils/Time"; import Toolkit from "../../utils/Toolkit"; import { JournalApi } from "../../api/JournalApi"; export type JournalListItem = { id: number; date: string; location?: string; idea?: string; thumbUrl?: string; } interface JournalListData { list: JournalListItem[]; isFetching: boolean; isFinished: boolean; page: JournalPage; searchValue: string; debouncedSearch?: any; } Component({ options: { styleIsolation: 'apply-shared' }, properties: { visible: { type: Boolean, value: false }, type: { type: String, value: undefined // NORMAL 或 PORTFOLIO,不传则获取所有类型 }, selectedId: { type: Number, value: undefined }, searchable: { type: Boolean, value: false // 是否显示搜索框 }, mode: { type: String, value: 'select' // 'select' 选择模式 或 'navigate' 跳转模式 } }, data: { list: [], isFetching: false, isFinished: false, page: { index: 0, size: 16, type: JournalPageType.PREVIEW, orderMap: { createdAt: OrderType.DESC } }, searchValue: "", debouncedSearch: undefined }, lifetimes: { ready() { // 创建防抖搜索函数 this.setData({ debouncedSearch: Toolkit.debounce( (keyword: string) => { this.resetAndSearch(keyword); }, false, // 不立即执行,等待输入停止 400 // 400ms 延迟 ) }) // 组件加载时就获取数据 this.fetch(); }, detached() { // 组件销毁时取消防抖 if (this.data.debouncedSearch) { this.data.debouncedSearch.cancel(); } } }, observers: { 'visible': function(visible: boolean) { // visible 从 false 变为 true 时,如果还没有数据则加载 if (visible && this.data.list.length === 0) { this.fetch(); } }, 'type': function() { this.resetPage(); } }, methods: { /** 重置搜索页面 */ resetPage() { const likeExample = this.data.searchValue ? { idea: this.data.searchValue, location: this.data.searchValue } : undefined; const equalsExample = this.properties.type ? { type: this.properties.type } : undefined; this.setData({ page: { index: 0, size: 16, type: JournalPageType.PREVIEW, equalsExample, likeExample, orderMap: { createdAt: OrderType.DESC } }, list: [], isFinished: false }); }, /** 获取数据 */ async fetch() { if (this.data.isFetching || this.data.isFinished) { return; } this.setData({ isFetching: true }); try { const pageResult = await JournalApi.getList(this.data.page); const list = pageResult.list; if (!list || list.length === 0) { this.setData({ isFinished: true, isFetching: false }); return; } const result = list.map((journal: any) => { const firstThumb = journal.items.find((item: any) => item.attachType === "THUMB"); return { id: journal.id, date: Time.toPassedDate(journal.createdAt), idea: journal.idea, location: journal.location, thumbUrl: firstThumb ? `${config.url}/attachment/read/${firstThumb.mongoId}` : undefined } as JournalListItem; }); this.setData({ page: { ...this.data.page, index: this.data.page.index + 1, type: JournalPageType.PREVIEW, equalsExample: this.data.page.equalsExample, likeExample: this.data.page.likeExample, orderMap: { createdAt: OrderType.DESC } }, list: this.data.list.concat(result), isFinished: list.length < this.data.page.size, isFetching: false }); } catch (error) { console.error("加载日记列表失败:", error); this.setData({ isFetching: false }); } }, /** 输入搜索 */ onSearchChange(e: WechatMiniprogram.CustomEvent) { const value = e.detail.value.trim(); this.setData({ searchValue: value }); // 使用防抖自动搜索(包括清空的情况) if (this.data.debouncedSearch) { this.data.debouncedSearch(value); } }, /** 提交搜索 */ onSearchSubmit(e: WechatMiniprogram.CustomEvent) { const value = e.detail.value.trim(); // 立即搜索,取消防抖 if (this.data.debouncedSearch) { this.data.debouncedSearch.cancel(); } this.resetAndSearch(value); }, /** 清空搜索 */ onSearchClear() { // 取消防抖,立即搜索 if (this.data.debouncedSearch) { this.data.debouncedSearch.cancel(); } this.resetAndSearch(""); }, /** 保留搜索关键字重新搜索 */ reSearch() { this.resetAndSearch(this.data.searchValue); }, /** 重置配置重新搜索 */ resetAndSearch(keyword: string) { const likeExample = keyword ? { idea: keyword, location: keyword } : undefined; const equalsExample = this.properties.type ? { type: this.properties.type } : undefined; this.setData({ searchValue: keyword, list: [], page: { index: 0, size: 16, type: JournalPageType.PREVIEW, equalsExample, likeExample, orderMap: { createdAt: OrderType.DESC } }, isFetching: false, isFinished: false }, () => { // 无论是否有搜索词,都重新获取列表 this.fetch(); }); }, onSelectItem(e: WechatMiniprogram.BaseEvent) { const { id } = e.currentTarget.dataset; if (this.properties.mode === 'navigate') { // 跳转模式:触发 navigate 事件 this.triggerEvent('navigate', { id }); } else { // 选择模式:触发 select 事件 this.triggerEvent('select', { id }); } }, onScrollToLower() { this.fetch(); } } });