// components/travel-location-popup/index.ts import { TravelLocation, TravelLocationTypeLabel, TravelLocationTypeIcon } from "../../types/Travel"; import { TravelLocationApi } from "../../api/TravelLocationApi"; import { MediaAttachType, PreviewImageMetadata } from "../../types/Attachment"; import { MediaItem, MediaItemType } from "../../types/UI"; import config from "../../config/index"; import Toolkit from "../../utils/Toolkit"; interface TravelLocationPopupData { locations: TravelLocation[]; currentLocationIndex: number; } Component({ properties: { visible: { type: Boolean, value: false }, ids: { type: Array, value: [] } }, data: { locations: [], currentLocationIndex: 0, }, observers: { async 'ids, visible'(ids: number[], visible: boolean) { if (visible && ids && 0 < ids.length) { wx.showLoading({ title: "加载中...", mask: true }); try { const locations = await TravelLocationApi.getListByIds(ids); locations.forEach(location => { location.typeLabel = location.type ? TravelLocationTypeLabel[location.type] : ""; location.typeIcon = location.type ? TravelLocationTypeIcon[location.type] : ""; // 处理附件数据 const attachments = location.items || []; const thumbItems = attachments.filter(item => item.attachType === MediaAttachType.THUMB); if (0 < thumbItems.length) { 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}`; 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; }); location.mediaItems = mediaItems; location.columnedItems = Toolkit.splitItemsIntoColumns(mediaItems, 3, (item) => { if (item.width && item.height && 0 < item.width) { return item.height / item.width; } return 1; }); } }); this.setData({ locations, currentLocationIndex: 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({ currentLocationIndex: e.detail.current }); }, /** 打开位置 */ openLocation() { const location = this.data.locations[this.data.currentLocationIndex]; if (location && location.lat && location.lng) { wx.openLocation({ latitude: location.lat, longitude: location.lng, name: location.title || "地点", address: location.location || "" }); } }, /** 预览媒体 */ previewMedia(e: WechatMiniprogram.BaseEvent) { const locations = this.data.locations; if (!locations || locations.length === 0) { return; } const { itemIndex } = e.currentTarget.dataset; const location = locations[this.data.currentLocationIndex]; const items = (location as any).mediaItems; if (!items || items.length === 0) { return; } 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: MediaItem) => { return { url: item.sourceURL, type: item.type === MediaItemType.IMAGE ? "image" : "video" }; }) as any; wx.previewMedia({ current: newCurrentIndex, sources }); } } });