// pages/main/travel-location-detail/index.ts import config from "../../../config/index"; import { TravelLocationApi } from "../../../api/TravelLocationApi"; import { TravelLocation, TravelLocationTypeIcon, TravelLocationTypeLabel } from "../../../types/Travel"; import { MediaAttachType, PreviewImageMetadata } from "../../../types/Attachment"; import { MapMarker, MediaItem, MediaItemType } from "../../../types/UI"; import Toolkit from "../../../utils/Toolkit"; interface TravelLocationView extends TravelLocation { /** 媒体列表 */ mediaItems?: MediaItem[]; } interface TravelLocationDetailData { /** 地点详情 */ location: TravelLocationView | null; /** 地点 ID */ locationId: string; /** 出行 ID */ travelId: string; /** 是否正在加载 */ isLoading: boolean; /** 错误信息 */ errorMessage: string; /** 地点类型标签映射 */ locationTypeLabels: typeof TravelLocationTypeLabel; /** 地点类型图标映射 */ locationTypeIcons: typeof TravelLocationTypeIcon; /** 媒体类型枚举 */ mediaItemTypeEnum: typeof MediaItemType; /** 地图标记 */ mapMarkers: MapMarker[]; /** 删除对话框可见性 */ deleteDialogVisible: boolean; /** 删除确认文本 */ deleteConfirmText: string; } Page({ data: { location: null, locationId: "", travelId: "", isLoading: true, errorMessage: "", locationTypeLabels: TravelLocationTypeLabel, locationTypeIcons: TravelLocationTypeIcon, mediaItemTypeEnum: { ...MediaItemType }, mapMarkers: [], deleteDialogVisible: false, deleteConfirmText: "" }, onLoad(options: any) { const { id, travelId } = options; if (id) { this.setData({ locationId: id, travelId: travelId || "" }); this.fetchDetail(id); } else { wx.showToast({ title: "参数错误", icon: "error" }); setTimeout(() => { wx.navigateBack(); }, 1500); } }, onShow() { // 页面显示时刷新数据(从编辑页返回时) if (this.data.locationId && !this.data.isLoading && this.data.location) { this.fetchDetail(this.data.locationId); } }, /** 获取地点详情 */ async fetchDetail(id: string) { this.setData({ isLoading: true, errorMessage: "" }); try { const location = await TravelLocationApi.getDetail(id); const thumbItems = (location.items || []).filter((item) => item.attachType === MediaAttachType.THUMB); const mediaItems: MediaItem[] = []; thumbItems.forEach((thumbItem) => { try { 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/"); mediaItems.push({ type: isVideo ? MediaItemType.VIDEO : MediaItemType.IMAGE, thumbURL, sourceURL, size: thumbItem.size || 0, attachmentId: thumbItem.id! }); } catch (parseError) { console.warn("解析附件元数据失败", parseError); } }); // 构建地图标记 const mapMarkers: MapMarker[] = []; if (location.lat !== undefined && location.lng !== undefined) { mapMarkers.push({ id: 0, latitude: location.lat, longitude: location.lng, width: 24, height: 30, customCallout: { anchorY: -2, anchorX: 0, display: "ALWAYS" } }); } this.setData({ location: { ...location, mediaItems }, travelId: location.travelId ? String(location.travelId) : this.data.travelId, mapMarkers }); } catch (error) { console.error("获取地点详情失败:", error); this.setData({ errorMessage: "加载失败,请稍后重试" }); wx.showToast({ title: "加载失败", icon: "error" }); } finally { this.setData({ isLoading: false }); } }, /** 重新加载 */ retryFetch() { if (this.data.locationId) { this.fetchDetail(this.data.locationId); } }, /** 编辑地点 */ toEdit() { const { location, travelId } = this.data; if (location && location.id) { wx.navigateTo({ url: `/pages/main/travel-location-editor/index?id=${location.id}&travelId=${travelId || location.travelId || ""}` }); } }, /** 出发(打开地图导航) */ navigate() { const { location } = this.data; if (location && location.lat !== undefined && location.lng !== undefined) { wx.openLocation({ latitude: location.lat, longitude: location.lng, name: location.title || "目的地", address: location.location || "", scale: 15 }); } else { wx.showToast({ title: "位置信息不完整", icon: "error" }); } }, /** 预览媒体 */ preview(e: WechatMiniprogram.BaseEvent) { const index = e.currentTarget.dataset.index; const { location } = this.data; if (!location || !location.mediaItems) { return; } const sources = location.mediaItems.map(item => ({ url: item.sourceURL, type: item.type })); const total = sources.length; const startIndex = Math.max(0, index - 25); const endIndex = Math.min(total, startIndex + 50); const newCurrentIndex = index - startIndex; wx.previewMedia({ current: newCurrentIndex, sources: sources.slice(startIndex, endIndex) as WechatMiniprogram.MediaSource[] }); }, /** 删除地点 */ deleteLocation() { this.setData({ deleteDialogVisible: true, deleteConfirmText: "" }); }, /** 取消删除 */ cancelDelete() { this.setData({ deleteDialogVisible: false, deleteConfirmText: "" }); }, /** 确认删除 */ confirmDelete() { const inputText = this.data.deleteConfirmText.trim(); if (inputText !== "确认删除") { wx.showToast({ title: "输入不匹配", icon: "error" }); return; } this.setData({ deleteDialogVisible: false }); this.executeDelete(); }, /** 执行删除 */ async executeDelete() { if (!this.data.location || !this.data.location.id) { return; } wx.showLoading({ title: "删除中...", mask: true }); try { await TravelLocationApi.delete(this.data.location.id); wx.showToast({ title: "删除成功", icon: "success" }); setTimeout(() => { wx.navigateBack(); }, 1500); } catch (error) { // 错误已由 Network 类处理 } finally { wx.hideLoading(); } }, /** 返回 */ async goBack() { Toolkit.async(() => wx.navigateBack()); // 微信 BUG,需要延时 } });