// pages/main/portfolio/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 IPortfolioData { page: JournalPage; list: Journal[]; isFetching: boolean; isFinished: boolean; stickyOffset: number; } Page({ data: { page: { index: 0, size: 8, type: JournalPageType.NORMAL, equalsExample: { type: "PORTFOLIO" }, orderMap: { createdAt: OrderType.DESC } }, list: [], isFetching: false, isFinished: false, stickyOffset: 0 }, onLoad() { Events.reset("JOURNAL_PORTFOLIO_REFRESH", () => { this.setData({ page: { index: 0, size: 8, type: JournalPageType.NORMAL, equalsExample: { type: "PORTFOLIO" }, orderMap: { createdAt: OrderType.DESC } }, list: [], isFetching: false, isFinished: false }); this.fetch(); }); this.getCustomNavbarHeight(); this.setData({ list: [] }) this.fetch(); }, 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 }); }); }, 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}`; const isVideo = metadata.sourceMimeType?.startsWith("video/"); return { type: 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: "PORTFOLIO" }, orderMap: { createdAt: OrderType.DESC } }, list: this.data.list.concat(list), isFinished: list.length < this.data.page.size, isFetching: false }); } catch (error) { console.error("加载 portfolio 列表失败:", 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 }) } });