// components/journal-detail-panel/index.ts import { Journal } from "../../types/Journal"; import config from "../../config/index"; import Toolkit from "../../utils/Toolkit"; import { MediaAttachType, PreviewImageMetadata } from "../../types/Attachment"; import { MediaItem, MediaItemType } from "../../types/UI"; import Time from "../../utils/Time"; import { JournalApi } from "../../api/JournalApi"; interface JournalDetailPanelData { journals: Journal[]; currentJournalIndex: number; } Component({ properties: { visible: { type: Boolean, value: false }, ids: { type: Array, value: [] }, mode: { type: String, value: "DATE" } }, data: { journals: [], currentJournalIndex: 0, }, observers: { async 'ids, visible'(ids: number[], visible: boolean) { if (visible && ids && 0 < ids.length) { wx.showLoading({ title: "加载中...", mask: true }); try { const journals = await JournalApi.getListByIds(ids); journals.forEach(journal => { journal.date = Time.toPassedDate(journal.createdAt); journal.time = Time.toTime(journal.createdAt); journal.datetime = Time.toPassedDateTime(journal.createdAt); const thumbItems = journal.items?.filter((item) => item.attachType === MediaAttachType.THUMB); if (!thumbItems) { return; } const mediaItems: MediaItem[] = thumbItems.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.mediaItems = mediaItems; // 为每个 journal 添加分列后的 mediaItems (journal as any).columnedMediaItems = Toolkit.splitItemsIntoColumns(mediaItems, 3, (item) => { // 计算相对高度:如果有宽高信息,使用宽高比;否则假设为正方形 if (item.width && item.height && 0 < item.width) { return item.height / item.width; } return 1; // 默认正方形 }); }) this.setData({ journals, currentJournalIndex: 0, }); wx.hideLoading(); } catch (err: any) { wx.hideLoading(); wx.showToast({ title: err.message || "加载失败", icon: "error" }); } } } }, methods: { /** 关闭详情 */ closeDetail() { this.triggerEvent("close"); }, /** swiper 切换事件 */ onSwiperChange(e: WechatMiniprogram.SwiperChange) { this.setData({ currentJournalIndex: e.detail.current }); }, /** 打开位置 */ openLocation(e: WechatMiniprogram.BaseEvent) { const { journalIndex } = e.currentTarget.dataset; if (!journalIndex && this.properties.mode !== "LOCATION") { return; } const journals = this.properties.journals as Journal[]; const journal = journals[journalIndex || 0]; if (journal.lat && journal.lng) { wx.openLocation({ latitude: journal.lat, longitude: journal.lng, }); } }, /** 预览媒体 */ previewMedia(e: WechatMiniprogram.BaseEvent) { const journals = this.data.journals; if (!journals || journals.length === 0) { return; } const { itemIndex } = e.currentTarget.dataset; const journal = journals[this.data.currentJournalIndex]; 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 }) } } });