// pages/journal/index.ts import Time from "../../../utils/Time"; import config from "../../../config/index" import Events from "../../../utils/Events"; import Toolkit from "../../../utils/Toolkit"; import { Journal, JournalPage, JournalPageType } from "../../../types/Journal"; import { OrderType } from "../../../types/Model"; import { PreviewImageMetadata } from "../../../types/Attachment"; import { MediaItem, MediaItemType } from "../../../types/UI"; import { JournalApi } from "../../../api/JournalApi"; interface JournalData { page: JournalPage; list: Journal[]; dateFilterMin: number; dateFilterMax: number; dateFilterAllows: number[]; dateFilterVisible: boolean; isFetching: boolean; isFinished: boolean; stickyOffset: number; isShowMoreMenu: boolean; menuTop: number; menuLeft: number; } Page({ data: { page: { index: 0, size: 8, type: JournalPageType.NORMAL, likeMap: { type: "NORMAL" }, orderMap: { createdAt: OrderType.DESC } }, list: [], dateFilterMin: new Date("2025/06/28 16:00:00").getTime(), dateFilterMax: new Date(2026, 1, 15).getTime(), dateFilterAllows: [ new Date(2025, 11, 15).getTime(), new Date(2025, 11, 20).getTime(), new Date(2025, 11, 10).getTime(), ], dateFilterVisible: false, isFetching: false, isFinished: false, stickyOffset: 0, isShowMoreMenu: false, menuTop: 0, menuLeft: 0 }, onLoad() { Events.reset("JOURNAL_REFRESH", () => { this.setData({ page: { index: 0, size: 8, type: JournalPageType.NORMAL, equalsExample: { type: "NORMAL" }, orderMap: { createdAt: OrderType.DESC } }, list: [], isFetching: false, isFinished: false }); this.fetch(); }); this.setData({ list: [] }) this.fetch(); }, onReady() { this.getCustomNavbarHeight(); }, onHide() { this.setData({ isShowMoreMenu: false }) }, onReachBottom() { this.fetch(); }, getCustomNavbarHeight() { const query = wx.createSelectorQuery(); query.select(".custom-navbar").boundingClientRect(); query.exec((res) => { const { height = 0 } = res[0] || {}; this.setData({ stickyOffset: height }); }); }, toggleMoreMenu() { if (!this.data.isShowMoreMenu) { // 打开菜单时计算位置 const query = wx.createSelectorQuery(); query.select(".more").boundingClientRect(); query.exec((res) => { if (res[0]) { const { top, left, height } = res[0]; this.setData({ isShowMoreMenu: true, menuTop: top + height + 16, // 按钮下方 8px menuLeft: left }); } }); } else { // 关闭菜单 this.setData({ isShowMoreMenu: false }); } }, /** 阻止事件冒泡 */ stopPropagation() { // 空函数,仅用于阻止事件冒泡 }, toCreater() { wx.navigateTo({ "url": "/pages/main/journal-editor/index?from=journal" }) }, toSearch() { wx.navigateTo({ url: "/pages/main/journal-search/index" }) }, toMap() { wx.navigateTo({ url: "/pages/main/journal-map/index" }) }, toDate() { wx.navigateTo({ url: "/pages/main/journal-date/index" }) }, 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; } list.forEach(journal => { const mediaItems = journal.items!.filter((item) => item.attachType === "THUMB").map((thumbItem, index) => { const metadata = (typeof thumbItem.metadata === "string" ? JSON.parse(thumbItem.metadata) : thumbItem.metadata) as PreviewImageMetadata; const thumbURL = `${config.url}/attachment/read/${thumbItem.mongoId}`; const sourceURL = `${config.url}/attachment/read/${metadata.sourceMongoId}`; return { type: metadata.isVideo ? MediaItemType.VIDEO : MediaItemType.IMAGE, thumbURL, sourceURL, size: thumbItem.size || 0, attachmentId: thumbItem.id, width: metadata.width, height: metadata.height, originalIndex: index } as MediaItem; }); journal.date = Time.toDate(journal.createdAt); journal.time = Time.toTime(journal.createdAt); journal.datetime = Time.toPassedDateTime(journal.createdAt); journal.mediaItems = mediaItems; journal.columnedItems = Toolkit.splitItemsIntoColumns(mediaItems, 3, (item) => { if (item.width && item.height && 0 < item.width) { return item.height / item.width; } return 1; }) }); this.setData({ page: { index: this.data.page.index + 1, size: 8, type: JournalPageType.NORMAL, equalsExample: { type: "NORMAL" }, orderMap: { createdAt: OrderType.DESC } }, list: this.data.list.concat(list), isFinished: list.length < this.data.page.size, isFetching: false }); } catch (error) { console.error("加载日记失败:", error); this.setData({ isFetching: false }); } }, preview(e: WechatMiniprogram.BaseEvent) { const { journalIndex, itemIndex } = e.currentTarget.dataset; const journal = this.data.list[journalIndex]; const items = journal.mediaItems!; const total = items.length; const startIndex = Math.max(0, itemIndex - 25); const endIndex = Math.min(total, startIndex + 50); const newCurrentIndex = itemIndex - startIndex; const sources = items.slice(startIndex, endIndex).map((item) => { return { url: item.sourceURL, type: item.type === MediaItemType.IMAGE ? "image" : "video" } }) as any; wx.previewMedia({ current: newCurrentIndex, sources }) }, openLocation(e: WechatMiniprogram.BaseEvent) { const { journalIndex } = e.currentTarget.dataset; const journal = this.data.list[journalIndex] as Journal; if (journal.lat && journal.lng) { wx.openLocation({ latitude: journal.lat, longitude: journal.lng, }); } }, });