184 lines
4.1 KiB
TypeScript
184 lines
4.1 KiB
TypeScript
// pages/main/travel-location-map/index.ts
|
|
|
|
import { TravelLocationApi } from "../../../api/TravelLocationApi";
|
|
import { TravelLocation, TravelLocationTypeLabel } from "../../../types/Travel";
|
|
import Toolkit from "../../../utils/Toolkit";
|
|
|
|
interface MapMarker {
|
|
id: number;
|
|
latitude: number;
|
|
longitude: number;
|
|
width: number;
|
|
height: number;
|
|
customCallout: {
|
|
anchorY: number;
|
|
anchorX: number;
|
|
display: string;
|
|
};
|
|
/** 该位置的所有地点 */
|
|
locations: TravelLocation[];
|
|
}
|
|
|
|
interface TravelMapData {
|
|
travelId: number;
|
|
centerLat: number;
|
|
centerLng: number;
|
|
scale: number;
|
|
markers: MapMarker[];
|
|
locations: TravelLocation[];
|
|
includePoints: Array<{ latitude: number; longitude: number }>;
|
|
isLoading: boolean;
|
|
detailVisible: boolean;
|
|
detailIds: number[];
|
|
}
|
|
|
|
Page({
|
|
data: <TravelMapData>{
|
|
travelId: 0,
|
|
centerLat: 39.908823,
|
|
centerLng: 116.397470,
|
|
scale: 13,
|
|
markers: [],
|
|
locations: [],
|
|
includePoints: [],
|
|
isLoading: true,
|
|
detailVisible: false,
|
|
detailIds: []
|
|
},
|
|
|
|
onLoad(options: any) {
|
|
const travelId = options.travelId ? parseInt(options.travelId) : 0;
|
|
if (travelId) {
|
|
this.setData({ travelId });
|
|
this.loadLocations(travelId);
|
|
} else {
|
|
wx.showToast({
|
|
title: "参数错误",
|
|
icon: "error"
|
|
});
|
|
setTimeout(() => {
|
|
wx.navigateBack();
|
|
}, 1500);
|
|
}
|
|
},
|
|
|
|
/** 加载所有地点 */
|
|
async loadLocations(travelId: number) {
|
|
this.setData({ isLoading: true });
|
|
|
|
try {
|
|
const result = await TravelLocationApi.getList({
|
|
index: 0,
|
|
size: 100,
|
|
equalsExample: {
|
|
travelId
|
|
}
|
|
});
|
|
|
|
// 过滤有位置信息的地点
|
|
const locations = result.list.filter(loc => loc.lat && loc.lng);
|
|
|
|
if (locations.length === 0) {
|
|
wx.showToast({
|
|
title: "暂无位置记录",
|
|
icon: "none"
|
|
});
|
|
this.setData({ isLoading: false });
|
|
return;
|
|
}
|
|
|
|
// 为每个地点添加类型标签
|
|
locations.forEach(location => {
|
|
(location as any).typeLabel = location.type ? TravelLocationTypeLabel[location.type] : "";
|
|
});
|
|
|
|
// 按位置分组,处理重叠地点
|
|
const locationMap = new Map<string, TravelLocation[]>();
|
|
locations.forEach(location => {
|
|
const key = `${location.lat},${location.lng}`;
|
|
if (!locationMap.has(key)) {
|
|
locationMap.set(key, []);
|
|
}
|
|
locationMap.get(key)!.push(location);
|
|
});
|
|
|
|
// 生成地图标记(每个唯一位置一个标记)
|
|
const markers: MapMarker[] = Array.from(locationMap.values()).map((locs, index) => ({
|
|
id: index,
|
|
latitude: locs[0].lat!,
|
|
longitude: locs[0].lng!,
|
|
width: 24,
|
|
height: 30,
|
|
customCallout: {
|
|
anchorY: -2,
|
|
// 随机错位避免近距离重叠
|
|
anchorX: Toolkit.random(-10, 10),
|
|
display: "ALWAYS"
|
|
},
|
|
locations: locs
|
|
}));
|
|
|
|
// 计算中心点(所有标记的平均位置)
|
|
const centerLat = locations.reduce((sum, l) => sum + l.lat!, 0) / locations.length;
|
|
const centerLng = locations.reduce((sum, l) => sum + l.lng!, 0) / locations.length;
|
|
|
|
// 缩放视野以包含所有标记点
|
|
const includePoints = locations.map((l) => ({
|
|
latitude: l.lat!,
|
|
longitude: l.lng!
|
|
}));
|
|
|
|
this.setData({
|
|
locations,
|
|
markers,
|
|
centerLat,
|
|
centerLng,
|
|
includePoints,
|
|
isLoading: false
|
|
});
|
|
} catch (err: any) {
|
|
wx.showToast({
|
|
title: "加载失败",
|
|
icon: "error"
|
|
});
|
|
this.setData({ isLoading: false });
|
|
}
|
|
},
|
|
|
|
/** 标记点击事件 */
|
|
onMarkerTap(e: any) {
|
|
const markerId = e.detail.markerId || e.markerId;
|
|
this.loadLocationDetail(markerId);
|
|
},
|
|
|
|
/** 气泡点击事件 */
|
|
onCalloutTap(e: any) {
|
|
const markerId = e.detail.markerId || e.markerId;
|
|
this.loadLocationDetail(markerId);
|
|
},
|
|
|
|
/** 加载位置详情 */
|
|
loadLocationDetail(markerId: number) {
|
|
const marker = this.data.markers[markerId];
|
|
if (!marker || !marker.locations || marker.locations.length === 0) {
|
|
return;
|
|
}
|
|
// 获取该标记点的所有地点 ID
|
|
const locationIds = marker.locations.map(loc => loc.id!).filter(id => id);
|
|
if (locationIds.length === 0) {
|
|
return;
|
|
}
|
|
this.setData({
|
|
detailVisible: true,
|
|
detailIds: locationIds
|
|
});
|
|
},
|
|
|
|
/** 关闭详情 */
|
|
closeDetail() {
|
|
this.setData({
|
|
detailVisible: false
|
|
});
|
|
}
|
|
});
|