findme-miniprogram-frontend/pages/map/map.js
2025-12-27 17:16:03 +08:00

6089 lines
No EOL
169 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 地图页面 - 高德地图SDK集成版本
const app = getApp();
const apiClient = require('../../utils/api-client.js');
const {
MapUtils,
MAP_CONFIG
} = require('../../utils/map-config.js');
const {
systemInfoHelper
} = require('../../utils/system-info-helper.js');
const config = require('../../config/config.js');
const authManager = require('../../utils/auth.js');
// 使用完整版本的高德地图SDK包含逆地理编码功能
const {
AMapWX
} = require('../../libs/amap-wx.js');
const {
MAP_FEED_MARKER_STYLE,
MAP_FEED_DEBOUNCE,
MAP_FEED_BUBBLE_LIMIT,
getFeedScalePreset,
buildBoundsPayload,
resolveFeedThumbnail,
buildCacheKey,
isCacheFresh
} = require('../../utils/map-feed-helpers.js');
// 导入合作商家数据模块
const {
getAllMerchants,
convertMerchantsToMarkers
} = require('../../utils/merchant-data.js');
const wsManager = require('../../utils/websocket-manager-v2.js');
const marker_blank = '/images/map/marker_blank.png';
const baseAmapUrl = config.api.baseAmapUrl;
const shouldUseMockData = !!config?.mockData;
const MAP_FEED_SINGLE_BASE_ID = 20000;
const MAP_FEED_CLUSTER_BASE_ID = 30000;
const MAP_FEED_ADMIN_BASE_ID = 40000;
const MAP_FEED_CLUSTER_STRANGER_ID = 50000;
const MAP_FEED_MARKER_STRANGER_ID = 70000;
const MAP_FEED_CLUSTER_FRIEND_ID = 60000;
const MAP_FEED_MARKER_FRIEND_ID = 80000;
function formatFeedCountLabel(count) {
const safeCount = Number(count) || 0;
if (safeCount <= 0) {
return '暂无内容';
}
if (safeCount >= 1000) {
return `${(safeCount / 1000).toFixed(1)}K 条内容`;
}
return `${safeCount} 条内容`;
}
function formatHeatLabel(score) {
if (score === undefined || score === null) {
return '热度更新中';
}
const value = Number(score);
if (Number.isNaN(value)) {
return '热度更新中';
}
const rounded = Math.round(value);
if (rounded >= 95) {
return `热度爆棚 · ${rounded}`;
}
if (rounded >= 80) {
return `热度很高 · ${rounded}`;
}
if (rounded >= 60) {
return `热度上升 · ${rounded}`;
}
return '新鲜出炉';
}
function formatRadiusLabel(radius) {
const safeRadius = Math.max(20, Math.round(Number(radius) || 0));
if (safeRadius >= 1000) {
return `范围约 ${(safeRadius / 1000).toFixed(1)} 公里`;
}
return `范围约 ${safeRadius}`;
}
function buildBubbleData(payload = {}) {
const radiusValue = payload.radius || 200;
const radiusLabel = payload.radiusLabel || formatRadiusLabel(radiusValue);
return {
title: payload.title || '附近热点',
subtitle: payload.subtitle || '',
chip: payload.chip || '',
heat: payload.heat || '',
radiusLabel,
createdAt: payload.createdAt,
nickname: payload.nickname,
content: payload.content,
avatar: payload.avatar,
thumbnail: payload.thumbnail || '',
feeds: payload.feeds || [],
location: payload.location || null,
radius: radiusValue,
type: payload.type || 'map-feed-cluster',
tone: payload.tone || 'sunset'
};
}
// 格式化后的模拟响应数据
const mockResponseStrangerClusters = {
"code": 200,
"message": "success",
"data": {
"displayMode": "friends",
"totalUsers": 25,
"displayedUsers": 20,
"onlineUsers": 15,
"userPoints": [{
"customId": "81149107",
"nickname": "用户7142",
"avatar": "https://oss.faxianwo.me/findme/images/731497293417c888e34942c14dd6e6ce.jpg",
"gender": 1,
"age": 25,
"latitude": 38.9042,
"longitude": 113.4074,
"address": "北京市朝阳区某某街道",
"district": "朝阳区",
"isOnline": true,
"lastSeen": 1706518800,
"stayTime": 3600,
"isMember": true,
"isFriend": true,
"relation": "friend",
"remark": "老同学",
"privacyLevel": 0,
"showPreciseLocation": true,
"distance": 150.5,
"distanceText": "150m",
"isCluster": false,
"clusterId": ""
}],
"clusters": [{
"clusterId": "cluster_001",
"latitude": 39.9042,
"longitude": 116.4074,
"userCount": 5,
"onlineCount": 3,
"avatarPreview": [
"https://example.com/avatar1.jpg",
"https://example.com/avatar2.jpg",
"https://example.com/avatar3.jpg"
],
"isFriendCluster": true,
"canExpand": true,
"radius": 100.0
}],
"bounds": {
"northEast": {
"latitude": 39.9142,
"longitude": 116.4174
},
"southWest": {
"latitude": 39.8942,
"longitude": 116.3974
}
},
"zoomLevel": 15,
"cacheHit": false,
"requestId": "req_1706518800123_4567",
"friendStats": {
"totalFriends": 25,
"onlineFriends": 15,
"offlineFriends": 10,
"nearbyFriends": 8,
"relationStats": {
"friend": 20,
"colleague": 3,
"family": 2
}
}
}
}
const mockResponseStranger = {
"code": 200,
"message": "success",
"data": {
"displayMode": "friends",
"totalUsers": 25,
"displayedUsers": 20,
"onlineUsers": 15,
"userPoints": [{
"customId": "81149107",
"nickname": "用户7142",
"avatar": "https://oss.faxianwo.me/findme/images/731497293417c888e34942c14dd6e6ce.jpg",
"gender": 1,
"age": 25,
"latitude": 39.9042,
"longitude": 116.4074,
"address": "北京市朝阳区某某街道",
"district": "朝阳区",
"isOnline": true,
"lastSeen": 1706518800,
"stayTime": 3600,
"isMember": true,
"isFriend": true,
"relation": "friend",
"remark": "老同学",
"privacyLevel": 0,
"showPreciseLocation": true,
"distance": 150.5,
"distanceText": "150m",
"isCluster": false,
"clusterId": ""
}],
"clusters": null,
"bounds": {
"northEast": {
"latitude": 39.9142,
"longitude": 116.4174
},
"southWest": {
"latitude": 39.8942,
"longitude": 116.3974
}
},
"zoomLevel": 15,
"cacheHit": false,
"requestId": "req_1706518800123_4567",
"friendStats": {
"totalFriends": 25,
"onlineFriends": 15,
"offlineFriends": 10,
"nearbyFriends": 8,
"relationStats": {
"friend": 20,
"colleague": 3,
"family": 2
}
}
}
}
const mockResponseDynamic = {
"code": 200,
"message": "success",
"data": {
"displayMode": "friends",
"totalUsers": 25,
"displayedUsers": 20,
"onlineUsers": 15,
"points": [{
"feedUuid": "81149107",
"nickname": "用户7142",
"thumbnail": "https://oss.faxianwo.me/findme/images/731497293417c888e34942c14dd6e6ce.jpg",
"gender": 1,
"age": 25,
"latitude": 39.9042,
"longitude": 116.4074,
"address": "北京市朝阳区某某街道",
"district": "朝阳区",
"isOnline": true,
"lastSeen": 1706518800,
"stayTime": 3600,
"isMember": true,
"isFriend": true,
"relation": "friend",
"remark": "老同学",
"privacyLevel": 0,
"showPreciseLocation": true,
"distance": 150.5,
"distanceText": "150m",
"isCluster": false,
"clusterId": ""
}],
"clusters": null,
"bounds": {
"northEast": {
"latitude": 39.9142,
"longitude": 116.4174
},
"southWest": {
"latitude": 39.8942,
"longitude": 116.3974
}
},
"zoomLevel": 15,
"cacheHit": false,
"requestId": "req_1706518800123_4567",
"friendStats": {
"totalFriends": 25,
"onlineFriends": 15,
"offlineFriends": 10,
"nearbyFriends": 8,
"relationStats": {
"friend": 20,
"colleague": 3,
"family": 2
}
}
}
}
const mockResponseFriendMarkerCluster = {
"code": 200,
"message": "success",
"data": {
"displayMode": "friends",
"totalUsers": 25,
"displayedUsers": 20,
"onlineUsers": 15,
"userPoints": [{
"customId": "39361203",
"nickname": "用户4023",
"avatar": "",
"gender": 1,
"age": 25,
"latitude": 39.9742,
"longitude": 116.9074,
"address": "北京市朝阳区某某街道",
"district": "朝阳区",
"isOnline": true,
"lastSeen": 1706518800,
"stayTime": 3600,
"isMember": true,
"isFriend": true,
"relation": "friend",
"remark": "老同学",
"privacyLevel": 0,
"showPreciseLocation": true,
"distance": 150.5,
"distanceText": "150m",
"isCluster": false,
"clusterId": ""
}],
"bounds": {
"northEast": {
"latitude": 39.9142,
"longitude": 116.4174
},
"southWest": {
"latitude": 39.8942,
"longitude": 116.3974
}
},
"clusters": [{
"clusterId": "cluster_001",
"latitude": 40.9042,
"longitude": 116.4074,
"userCount": 5,
"onlineCount": 3,
"avatarPreview": [
"https://example.com/avatar1.jpg",
"https://example.com/avatar2.jpg",
"https://example.com/avatar3.jpg"
],
"isFriendCluster": true,
"canExpand": true,
"radius": 100.0
}],
"zoomLevel": 15,
"cacheHit": false,
"requestId": "req_1706518800123_4567",
"friendStats": {
"totalFriends": 25,
"onlineFriends": 15,
"offlineFriends": 10,
"nearbyFriends": 8,
"relationStats": {
"friend": 20,
"colleague": 3,
"family": 2
}
}
}
}
const mockResponseFriend = {
"code": 200,
"message": "success",
"data": {
"displayMode": "friends",
"totalUsers": 25,
"displayedUsers": 20,
"onlineUsers": 15,
"userPoints": [{
"customId": "81149107",
"nickname": "用户7142",
"avatar": "",
"gender": 1,
"age": 25,
"latitude": 40.9042,
"longitude": 116.4074,
"address": "北京市朝阳区某某街道",
"district": "朝阳区",
"isOnline": true,
"lastSeen": 1706518800,
"stayTime": 3600,
"isMember": true,
"isFriend": true,
"relation": "friend",
"remark": "老同学",
"privacyLevel": 0,
"showPreciseLocation": true,
"distance": 150.5,
"distanceText": "150m",
"isCluster": false,
"clusterId": ""
}],
"clusters": null,
"bounds": {
"northEast": {
"latitude": 39.9142,
"longitude": 116.4174
},
"southWest": {
"latitude": 39.8942,
"longitude": 116.3974
}
},
"zoomLevel": 15,
"cacheHit": false,
"requestId": "req_1706518800123_4567",
"friendStats": {
"totalFriends": 25,
"onlineFriends": 15,
"offlineFriends": 10,
"nearbyFriends": 8,
"relationStats": {
"friend": 20,
"colleague": 3,
"family": 2
}
}
}
}
Page({
data: {
showCameraAction: false, // 拍照弹窗
isLoggedIn: app.globalData.isLoggedIn, // 登录状态
isDarkMode:false,
amapFun: null,
poiAroundList: [],
showPoiAroundModal: false,
// 地图配置
longitude: 0,
latitude: 0,
currentMapScale: 12, // 初始缩放级别,低于自动切换阈值
//商家信息
merchantMarkers: [],
merchantList: [], // 商家列表数据
merchantInfoModalVisible: false,
selectedMerchant: null,
activeMerchantId: null, // 当前激活的商户ID
// 静态数据
staticDataMarkers: [], // 存储静态数据标记
// 位置信息
currentAddress: '获取位置中...',
addressDetail: null,
accuracy: 0,
currentDistrict: '新市区', // 设置默认地点名称
currentCity: '乌鲁木齐', // 设置默认城市名称
weatherInfo: null,
// SDK状态
amapReady: false,
amapError: null,
// 好友数据
friendsData: [],
// 用户信息
userInfo: null,
userAvatar: '',
avatar: '',
avatarUrl: '',
showUserLocationIndicator: false,
showMyAvatarMarker: true,
myLocation: null, // 保存自己的位置信息
// 地图样式控制
enableSatellite: false,
currentMapType: 'standard', // standard, satellite, traffic, transit
shouldFollowLocation: true, // 控制是否跟随用户位置移动
autoSatelliteZoom: 18, // 超过此缩放级别自动切换卫星图
maxScale: 22, // 地图最大缩放级别设置为22以提高卫星图清晰度
mapTheme: 'light', // 地图主题light 或 dark
// 系统适配
statusBarHeight: 44,
menuButtonHeight: 32,
navBarHeight: 88,
safeAreaBottom: 0,
// UI状态
selectedUser: null,
currentFilter: 'friends',
friendsCount: 0,
strangersCount: 0,
showFilterModal: false,
// 🔥 浮动UI状态
isOnline: true,
friendRequestCount: 0,
unreadMessageCount: 0,
nearbyCount: 0,
// 地址信息
weather: null,
// 默认位置(如果定位失败)
defaultLocation: {
latitude: 39.908692,
longitude: 116.397979,
address: '北京市'
},
// 地图动态相关
locationDynamics: [], // 存储地图上的所有动态
showDynamicInputModal: false, // 显示动态输入弹窗
currentDynamicLocation: null, // 当前要发布动态的位置
dynamicContent: '', // 动态内容
selectedDynamic: null, // 当前选中的动态
showDynamicDetailModal: false, // 显示动态详情弹窗
mapFeedMode: 'nearby',
mapFeedLevel: 'street',
mapFeedLoading: false,
mapFeedError: '',
mapFeedMarkers: [],
mapFeedPreviewList: [],
activeFeedBubble: null,
activeFeedBubbleLoading: false,
hasUserInteractedWithMap: false,
poiDetail: {
address: '', // 预先定义 address 属性
name: ''
},
poiDetailShow: false,
showPoiRemindModal: false,
poiRemindRadius: 300, // 默认300米
poiRemindCircle: null,
poiRemindMode: ['arrive'], // 多选,初始为到达
showFriendSelectModal: false,
lastPoiForRemind: null,
allFriendsList: [], // 新增:用于好友选择弹窗的模拟数据
// 新增
friendSearchText: '',
filteredFriendsList: [],
showLocationMarkModal: false,
locationMarkSearchText: '',
locationMarkList: [],
filteredLocationMarkList: [],
// 搜索相关状态
showSearchBox: false,
searchKeyword: '',
searchResults: [], // 存储搜索结果
searchResultInfoModalVisible: false,
placeMarkId: '',
// 更多菜单相关状态
showMoreMenu: false,
// 地图设置相关状态
showMapSettings: false,
isClosingMapSettings: false,
mapStyle:null,
// POI提醒相关状态
poiRemindSelectedFriends: [], // 存储已选择的好友信息
// 地点收藏栏相关状态
showLocationFavoriteBar: false, // 控制收藏栏显示
locationFavoriteTab: 'favorite', // 当前选中的标签nearby或favorite
locationFavorites: [], // 所有收藏地点
filteredLocationFavorites: [], // 过滤后的收藏地点
locationFavoriteSearch: '', // 搜索关键词
showTraffic: false, // 默认不显示交通拥堵
merchantName: "",
merchant: "",
merchantAddress: "",
shareModalVisible: true,
shareShareVisible: false,
searchResultNavigationVisible: false,
selectResult: null,
addressIsFavorited: false,
longitude: 116.404, // 初始经度(示例:北京)
latitude: 39.915, // 初始纬度
metric: "0米", // 米/千米
imperial: "0英尺", // 英尺
allMarkers: [],
userMarker: null,
renderKey: null,
poiDetailAddress: '详细地址',
busStops: [], // 公交站点标记
busLines: [], // 公交线路
isBusLayerVisible: false, // 公交图层显示状态
busDataLoading: false, // 公交数据加载状态
lastBusRegion: null, // 上一次加载公交数据的区域
busDataExpireTime: 300000, // 公交数据缓存过期时间(5分钟)
busDataCache: new Map(),
mapClickCollect: '收藏',
// 数据存储
busLines: [],
subwayLines: [],
markers: [],
polylines: [],
// 存储当前设备方向角度0-360°
// 标记是否支持设备方向
isSupport: false,
// 标记是否已获取权限
hasPermission: false,
mapClickCollect: '收藏',
isMapClick: false,
markers: [],
activeFeedBubbleSingle: null,
clusterMarkers: [], // 新增:存储聚合点 marker
polygons: [], // 存储多边形覆盖物
clusterThreshold: 1000, //陌生人和好友聚合的临界值单位米
activeFeedSingleVisible: false,
cacheEntryString: '',
directonAngle: -1,
mapFeedVisible: false,
startY: 0,
modalTranslateY: 0,
isMoving: false,
shareOptions: [{
type: "wechat",
icon: "/images/map/Wechat_logo.png",
name: "微信"
},
{
type: "douyin",
icon: "/images/map/Tiktok_logo.png",
name: "抖音"
},
{
type: "weibo",
icon: "/images/map/Microblog_logo.png",
name: "微博"
},
{
type: "email",
icon: "/images/map/Email_logo.png",
name: "邮箱"
},
{
type: "qq",
icon: "/images/map/QQ_logo.png",
name: "QQ"
},
{
type: "copy",
icon: "/images/map/Copy_logo.png",
name: "复制"
},
],
},
// 显示地点收藏栏
onOpenLocationFavoriteBar() {
this.initLocationFavorites();
this.setData({
showLocationFavoriteBar: true,
locationFavoriteTab: 'favorite',
locationFavoriteSearch: ''
});
},
// 关闭地点收藏栏
onCloseLocationFavoriteBar() {
this.setData({
showLocationFavoriteBar: false
});
},
// 初始化收藏地点数据
initLocationFavorites() {
// 创建一些模拟数据
if (!shouldUseMockData) {
this.setData({
locationFavorites: [],
filteredLocationFavorites: []
});
return;
}
},
// 切换标签
onChangeLocationFavoriteTab(e) {
const tab = e.currentTarget.dataset.tab;
this.setData({
locationFavoriteTab: tab,
locationFavoriteSearch: ''
});
// 根据标签切换显示不同的内容
if (tab === 'nearby') {
// 这里可以添加获取附近地点的逻辑
// 暂时使用收藏地点数据
this.setData({
filteredLocationFavorites: this.data.locationFavorites
});
} else if (tab === 'favorite') {
this.setData({
filteredLocationFavorites: this.data.locationFavorites.filter(item => item.isFavorited)
});
}
},
previewImageAvatar(e) {
try {
// 获取当前点击的图片索引和动态索引
const avatar = e.currentTarget.dataset.avatar;
// 🔥 设置标志,防止预览关闭后触发页面刷新
this._skipNextOnShowReload = true;
const imageUrls=[avatar];
// 调用微信小程序的图片预览API
wx.previewImage({
current: avatar,
urls: imageUrls,
success: () => {
// 预览打开成功,标志已设置,关闭时会触发 onShow
},
fail: (err) => {
console.error('图片预览失败:', err);
// 预览失败,清除标志
this._skipNextOnShowReload = false;
wx.showToast({
title: '预览图片失败',
icon: 'none'
});
}
});
} catch (error) {
console.error('图片预览过程中出错:', error);
// 出错时清除标志
this._skipNextOnShowReload = false;
wx.showToast({
title: '预览图片失败',
icon: 'none'
});
}
},
// 地点收藏搜索
onLocationFavoriteSearch(e) {
const searchText = e.detail.value;
this.setData({
locationFavoriteSearch: searchText
});
// 根据搜索关键词筛选地点
let filtered = [];
if (this.data.locationFavoriteTab === 'nearby') {
filtered = this.data.locationFavorites.filter(item =>
item.name.includes(searchText) || item.address.includes(searchText)
);
} else {
filtered = this.data.locationFavorites.filter(item =>
item.isFavorited && (item.name.includes(searchText) || item.address.includes(searchText))
);
}
this.setData({
filteredLocationFavorites: filtered
});
},
// 清除地点收藏搜索
onClearLocationFavoriteSearch() {
this.setData({
locationFavoriteSearch: '',
filteredLocationFavorites: this.data.locationFavoriteTab === 'nearby' ?
this.data.locationFavorites : this.data.locationFavorites.filter(item => item.isFavorited)
});
},
// 切换地点收藏状态
onToggleLocationFavorite(e) {
const id = e.currentTarget.dataset.id;
const locationFavorites = this.data.locationFavorites.map(item => {
if (item.id === id) {
item.isFavorited = !item.isFavorited;
}
return item;
});
// 根据当前标签和搜索词更新过滤后的列表
let filtered = [];
if (this.data.locationFavoriteTab === 'nearby') {
filtered = locationFavorites.filter(item =>
item.name.includes(this.data.locationFavoriteSearch) ||
item.address.includes(this.data.locationFavoriteSearch)
);
} else {
filtered = locationFavorites.filter(item =>
item.isFavorited && (item.name.includes(this.data.locationFavoriteSearch) ||
item.address.includes(this.data.locationFavoriteSearch))
);
}
this.setData({
locationFavorites: locationFavorites,
filteredLocationFavorites: filtered
});
},
// 显示筛选选项弹窗
showFilterOptions() {
this.setData({
showFilterModal: true
});
},
// 隐藏筛选选项弹窗
hideFilterOptions() {
this.setData({
showFilterModal: false
});
},
initMapFeedState() {
if (this.mapFeedDebounceTimer) {
clearTimeout(this.mapFeedDebounceTimer);
}
this.mapFeedDebounceTimer = null;
this.mapFeedCache = new Map();
this.mapFeedMarkerLookup = new Map();
this.mapStrangerMarkerLookup = new Map();
this.setData({
mapFeedMarkers: [],
mapFeedPreviewList: [],
activeFeedBubble: null,
mapFeedMode: 'nearby',
mapFeedLevel: 'street',
mapFeedError: '',
mapFeedLoading: false
});
},
// 显示拍照功能弹窗
showCameraActionSheet() {
this.setData({
showCameraAction: true
});
},
// 隐藏拍照功能弹窗
hideCameraActionSheet() {
this.setData({
showCameraAction: false
});
},
// 拍摄照片
takePhoto() {
this.hideCameraActionSheet();
// 检查登录状态
// 未登录进入登录页面
if (!authManager.isLoggedIn()) {
wx.navigateTo({
url: '/pages/login/login'
});
} else {
wx.navigateTo({
url: '/subpackages/media/camera/camera' // 已登录用户跳转到拍摄页面
});
}
},
// 从相册选择
chooseImage() {
this.hideCameraActionSheet();
// 检查登录状态
// 未登录进入登录页面
if (!authManager.isLoggedIn()) {
wx.navigateTo({
url: '/pages/login/login'
});
} else {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0];
// 显示加载提示
wx.showLoading({
title: '上传中...',
mask: true
});
// 处理选择的图片
this.uploadImage(tempFilePath)
.then(imageUrl => {
wx.hideLoading();
wx.navigateTo({
url: `/pages/edits/edits?imagePath=${encodeURIComponent(imageUrl)}`,
success: () => {
wx.showToast({
title: '上传成功',
icon: 'success'
});
},
fail: (err) => {
console.error('跳转发布页失败:', err);
wx.showToast({
title: '跳转失败,请重试',
icon: 'none'
});
}
});
})
.catch(error => {
wx.hideLoading();
console.error('上传过程出错:', error);
wx.showToast({
title: error.message || '上传失败,请重试',
icon: 'none'
});
});
},
fail: (error) => {
console.error('选择图片失败:', error);
wx.showToast({
title: '选择图片失败',
icon: 'none'
});
}
});
}
},
// 上传图片
uploadImage(tempFilePath) {
return new Promise((resolve, reject) => {
try {
wx.uploadFile({
url: `${config.api.baseUrl}/api/v1/file/upload`,
filePath: tempFilePath,
name: 'file',
formData: {
file_type: 'image',
usage_type: 'feed'
},
header: {
'Authorization': `Bearer ${apiClient.getToken()}`
},
success: (uploadRes) => {
// 🔥 统一处理401 - 使用apiClient的统一处理
if (apiClient.is401Error(uploadRes)) {
const app = getApp();
const isLoggedIn = app?.globalData?.isLoggedIn || false;
apiClient.handle401Error(isLoggedIn);
// 对已登录用户抛出错误
if (isLoggedIn) {
reject(new Error('登录已过期,请重新登录'));
} else {
// 对未登录用户返回空数据
resolve(null);
}
return;
}
// 解析响应数据
let result;
try {
result = JSON.parse(uploadRes.data);
} catch (e) {
console.error('解析响应JSON失败响应数据:', uploadRes.data);
reject(new Error('解析服务器响应失败'));
return;
}
// 上传成功
if (uploadRes.statusCode === 200 && result.code === 0) {
if (result.data && result.data.file_url) {
resolve(result.data.file_url);
} else {
reject(new Error('服务器未返回图片URL'));
}
} else {
reject(new Error(result.msg || '上传失败'));
}
},
fail: (error) => {
console.error('上传请求失败:', error);
let errorMsg = '网络请求失败,请检查网络';
if (error.errMsg) {
errorMsg = error.errMsg;
}
reject(new Error(errorMsg));
}
});
} catch (error) {
console.error('上传图片到服务器失败:', error);
reject(error);
}
});
},
// 显示筛选选项弹窗
showFilterOptions() {
this.setData({
showFilterModal: true
});
},
// 隐藏筛选选项弹窗
hideFilterOptions() {
this.setData({
showFilterModal: false
});
},
onLoad() {
console.log("on-->" + "onLoad");
// 初始化模拟天气数据,确保天气信息始终显示
if (shouldUseMockData) {
const mockWeatherInfo = {
temperature: 25,
weather: '晴',
icon: '☀️',
isCloudIcon: false,
humidity: 45,
windSpeed: 3.2,
windDir: '东南风',
aqi: 85,
city: this.data.currentCity || '乌鲁木齐',
updateTime: new Date().toLocaleTimeString('zh-CN')
};
this.setData({
weatherInfo: mockWeatherInfo
});
console.debug('✅ 已设置模拟天气数据:', mockWeatherInfo);
} else {
this.setData({
weatherInfo: null
});
}
this.amapFun = new AMapWX({
key: config.amapKey
});
// 使用已经创建的系统信息辅助实例
this.systemInfoHelper = systemInfoHelper;
// 获取系统信息和胶囊按钮位置
const systemInfo = this.systemInfoHelper.getSystemInfoSync();
const menuButtonInfo = this.systemInfoHelper.getMenuButtonBoundingClientRect();
// 计算导航栏高度和胶囊位置信息
const navBarHeight = this.systemInfoHelper.getNavBarHeight(systemInfo);
this.setData({
statusBarHeight: systemInfo.statusBarHeight || 44,
navBarHeight: navBarHeight,
windowHeight: systemInfo.windowHeight || 667,
safeAreaBottom: systemInfo.safeArea?.bottom || 0,
menuButtonTop: menuButtonInfo.top || 48,
menuButtonRight: menuButtonInfo.right || 365,
menuButtonWidth: menuButtonInfo.width || 87,
menuButtonHeight: menuButtonInfo.height || 32
});
// 初始化API客户端
this.apiClient = apiClient;
// 初始化地图动态状态
this.initMapFeedState();
// 初始化静态数据
this.initStaticData();
// 初始化合作商家数据
this.initMerchantMarkers();
// 初始化地图上下文
this.mapCtx = wx.createMapContext('main-map', this);
// this.mapCtx.initMarkerCluster({
// enableDefaultStyle: false, // 使用默认聚合样式
// zoomOnClick: true, // 点击聚合点自动放大
// gridSize: 60, // 聚合计算网格大小单位px
// complete(res) {}
// });
this.initSystemInfo();
this.initAMapSDK();
console.log("onload----->" + Date.now());
this.requestLocationPermission();
this.lastFriendsFetch = 0;
this.lastNearbyFetch = 0;
this.lastWeatherFetch = 0;
this.lastLocationSnapshot = null;
// 🔥 加载浮动UI相关数据
this.loadFloatingUIData();
// 注入模拟好友数据
if (shouldUseMockData) {
const mockFriends = [{
userId: 'u1',
nickname: '小明',
avatarUrl: ''
},
{
userId: 'u2',
nickname: '小红',
avatarUrl: ''
},
{
userId: 'u3',
nickname: '小刚',
avatarUrl: ''
},
{
userId: 'u4',
nickname: '小美',
avatarUrl: ''
},
{
userId: 'u5',
nickname: '小强',
avatarUrl: ''
}
];
this.setData({
allFriendsList: mockFriends,
filteredFriendsList: mockFriends
});
const mockLocationMarkList = [{
id: 'loc1',
lat: 44.897383746906186,
lng: 82.07800276534772,
name: '博尔塔拉长城医院',
remindFriends: [{
userId: 'u1',
avatarUrl: ''
},
{
userId: 'u2',
avatarUrl: ''
}
],
remindType: 'arrive'
},
{
id: 'loc2',
lat: 44.90334720165053,
lng: 82.06464725905994,
name: '博乐市第八中学',
remindFriends: [{
userId: 'u3',
avatarUrl: ''
}],
remindType: 'leave'
}
];
this.setData({
locationMarkList: mockLocationMarkList,
filteredLocationMarkList: mockLocationMarkList
});
} else {
this.setData({
allFriendsList: [],
filteredFriendsList: [],
locationMarkList: [],
filteredLocationMarkList: []
});
this.setData({
isBusLayerVisible: wx.getStorageSync('busLayerState') || false
});
}
wx.showShareMenu({
withShareTicket: true, // 可选,是否带上 shareTicket
menus: ['shareAppMessage', 'shareTimeline'] // 指定分享菜单,'shareAppMessage' 用于分享到聊天
})
// 初始化计算
this.updateScale();
this.startListening();
// this.getCityBoundary("大理");
this.loadUserInfo();
// this.getInitialOrientation();
this.checkSystemTheme();
},
// 核心:判断系统主题 + 手机系统类型(安卓/苹果)
checkSystemTheme() {
try {
// 同步获取系统信息(含主题、系统类型等)
const systemInfo = wx.getSystemInfoSync();
// 1. 判断手机系统类型(安卓/苹果)
const isIOS = /ios/i.test(systemInfo.system); // 匹配 iOS 系统(忽略大小写)
const isAndroid = /android/i.test(systemInfo.system); // 匹配 Android 系统(忽略大小写)
// 2. 判断系统主题(深色/浅色)
const isDark = systemInfo.theme === 'dark';
// 3. 更新数据(同时保存系统类型和主题状态)
if(isAndroid){
this.setData({
isDarkMode: false,
isIOS: isIOS,
isAndroid: isAndroid
});
}else{
this.setData({
isDarkMode: isDark,
isIOS: isIOS,
isAndroid: isAndroid
});
}
// 打印日志(清晰展示系统类型+主题)
console.log(
'当前设备:',
isIOS ? '苹果手机iOS' : isAndroid ? '安卓手机Android' : '其他设备',
' | 系统主题:',
isDark ? '深色模式' : '浅色模式'
);
} catch (err) {
// 异常处理(低版本微信/获取系统信息失败)
console.error('获取系统信息(主题+设备类型)失败:', err);
this.setData({
isDarkMode: false, // 异常时默认浅色模式
isIOS: false,
isAndroid: false
});
}
},
async loadUserInfo() {
try {
// 先从全局数据获取
let userInfo = getApp().globalData.userInfo;
// 如果全局没有完整信息从API获取
// const response = await this.apiClient.getUserInfo();
// console.log("info--->2"+response);
// if (!userInfo) {
const response = await apiClient.getUserInfo();
if (response && response.code === 0) {
userInfo = {
...userInfo,
user: response.data
};
// 更新全局数据
getApp().globalData.userInfo = userInfo;
console.log("info--->1" + response);
}
// }
this.setData({
userInfo: userInfo
});
this.initWebSocketFriendFeatures();
} catch (error) {
console.error('❌ 获取用户信息失败:', error);
// 不影响主要功能,继续加载好友列表
}
},
getInitialOrientation() {
let that = this;
return new Promise((resolve, reject) => {
// 先检查设备是否支持罗盘(更准确的方向传感器)
wx.getSystemInfo({
success: (sysInfo) => {
// 扩展支持检测:同时检查罗盘和设备运动传感器
const supportCompass = typeof wx.onCompassChange === 'function';
const supportMotion = typeof wx.onDeviceMotionChange === 'function';
if (!supportCompass && !supportMotion) {
console.warn('设备不支持方向感应,使用默认方向');
resolve(0); // 返回默认角度(正北)
return;
}
// 优先使用罗盘(方向更稳定)
if (supportCompass) {
const compassListener = (res) => {
// 罗盘返回的是与正北的夹角0-360°
const angle = Math.round(res.direction);
if (typeof angle === 'number' && !isNaN(angle)) {
this.setData({
directonAngle: angle
});
this.updateArrowDirection(angle);
wx.offCompassChange(compassListener); // 移除监听
resolve(angle);
}
};
wx.onCompassChange(compassListener);
// 启动罗盘(部分设备需要主动启动)
wx.startCompass({
success: () => {},
fail: () => {
wx.offCompassChange(compassListener);
fallbackToMotionSensor(resolve); // 启动失败时降级
}
});
} else {
// 无罗盘时使用设备运动传感器
fallbackToMotionSensor(resolve);
}
// 超时处理
setTimeout(() => {
if (supportCompass) wx.offCompassChange();
if (supportMotion) wx.offDeviceMotionChange();
console.warn('获取方向超时,使用默认值');
resolve(0);
}, 3000);
},
fail: (err) => {
console.error('获取系统信息失败', err);
resolve(0); // 系统信息获取失败时仍返回默认值
}
});
// 设备运动传感器降级处理
function fallbackToMotionSensor(resolve) {
const motionListener = (deviceData) => {
// alpha值绕z轴旋转角度0-360°
if (typeof deviceData.alpha === 'number' && !isNaN(deviceData.alpha)) {
const angle = Math.round(deviceData.alpha);
console.log("angle--->" + angle);
that.setData({
directonAngle: angle
});
that.updateArrowDirection(angle);
// wx.offDeviceMotionChange(motionListener);
resolve(angle);
}
};
wx.onDeviceMotionChange(motionListener);
// 启动设备运动监听(部分设备需要)
// wx.startDeviceMotionListening({
// interval: 'normal',
// success: () => {},
// fail: (err) => {
// wx.offDeviceMotionChange(motionListener);
// console.warn('设备运动监听启动失败', err);
// resolve(0);
// }
// });
}
});
},
initWebSocketFriendFeatures() {
try {
console.log('🔌 初始化WebSocket好友事件监听器');
// 绑定处理函数到 this方便后续移除
this.handleNotificationMessage = this.handleNotificationMessage.bind(this);
wsManager.on('user_offline', this.handleNotificationMessage);
} catch (error) {
console.error('初始化WebSocket功能失败:', error);
}
},
// 处理通知消息
handleNotificationMessage(msg) {
try {
console.log('🔔 收到心跳---->:', msg);
} catch (error) {
console.error('处理通知消息失败:', error);
}
},
// 调用高德接口获取城市边界
getCityBoundary(cityName) {
let that = this;
wx.request({
url: baseAmapUrl + '/config/district',
data: {
keywords: cityName,
subdistrict: 0, // 不返回子区域
extensions: 'all', // 必须为all才能获取polyline
key: config.amapKey // 替换为你的Key
},
success: (res) => {
if (res.data.status === '1' && res.data.districts.length > 0) {
const district = res.data.districts[0];
const polyline = district.polyline; // 边界坐标串
// 解析为小程序polygons格式
const polygons = that.parsePolylineToPolygons(polyline, district.adcode);
// 更新地图数据
this.setData({
polygons: polygons
});
}
},
fail: (err) => {
console.error('获取边界失败:', err);
}
});
},
// 解析高德接口返回的polyline为小程序polygons格式
parsePolylineToPolygons(polyline, cityId) {
const polygons = [];
// 按 | 分割多个环(每个环是一个独立多边形)
const rings = polyline.split('|');
rings.forEach((ring, index) => {
// 按 ; 分割单个环的坐标点
const pointStrs = ring.split(';');
// 转换为 { longitude, latitude } 格式
const points = pointStrs.map(pointStr => {
const [lng, lat] = pointStr.split(',').map(Number);
return {
longitude: lng,
latitude: lat
};
});
// 添加到polygons数组可自定义样式
polygons.push({
id: `${cityId}_${index}`, // 唯一标识(主区域+子区域区分)
points,
fillColor: '#1098B0',
strokeColor: '#0DD2FC',
strokeWidth: 2,
fillOpacity: 0.6,
strokeDasharray: [5, 5]
});
});
return polygons;
},
/**
* 生成区域唯一标识
* @param {Object} region - 地图区域
* @returns {String} 区域标识
*/
getRegionKey(region) {
// 四舍五入到小数点后4位减少精度导致的重复
return [
Math.round(region.southwest.latitude * 10000) / 10000,
Math.round(region.southwest.longitude * 10000) / 10000,
Math.round(region.northeast.latitude * 10000) / 10000,
Math.round(region.northeast.longitude * 10000) / 10000
].join(',');
},
/**
* 检查是否同一区域
* @param {String} regionKey - 区域标识
* @returns {Boolean} 是否同一区域
*/
isSameRegion(regionKey) {
return this.data.lastBusRegion === regionKey;
},
/**
* 检查缓存是否过期
* @param {String} regionKey - 区域标识
* @returns {Boolean} 是否过期
*/
isCacheExpired(regionKey) {
const cache = this.busDataCache.get(regionKey);
if (!cache) return true;
return Date.now() - cache.timestamp > this.data.busDataExpireTime;
},
// 4. 更新箭头方向(根据实际业务场景修改) 可旋转但是会重复多个
updateArrowDirection(angle) {
const targetIndex = this.data.markers.findIndex(marker => marker.id === 1);
if (targetIndex !== -1) {
this.setData({
directonAngle: angle,
[`markers[${targetIndex}].directonAngle`]: angle,
[`markers[${targetIndex}].directionPath`]: '/images/map/direction_arrow.png'
});
}
},
// 页面隐藏/卸载时停止监听(必须做,否则会耗电)
onHide() {
this.stopListening();
},
onUnload() {
this.stopListening();
// 移除 WebSocket 通知监听器
try {
if (this.handleNotificationMessage) {
wsManager.off('user_offline', this.handleNotificationMessage);
console.log('✅ 已移除 WebSocket 通知监听器');
}
} catch (error) {
console.error('移除 WebSocket 通知监听器失败:', error);
}
},
// 停止监听的工具方法
startListening() {
// 停止可能存在的旧监听(避免重复监听)
wx.stopDeviceMotionListening({});
// 新增:记录上一次的角度值,用于判断角度变化是否超过阈值
let lastAngle = null;
// 记录上次更新时间
let lastUpdateTime = 0;
// 角度变化阈值(度),超过此值才更新
const ANGLE_THRESHOLD = 5;
// 最小更新间隔(毫秒),避免过于频繁更新
const MIN_UPDATE_INTERVAL = 1000;
// 启动新监听
wx.startDeviceMotionListening({
interval: 'game', // 高频监听(适合实时方向更新)
success: () => {
console.log('方向监听启动成功');
// 监听方向变化事件
this.motionListener = wx.onDeviceMotionChange((res) => {
// res.alpha设备绕垂直轴旋转角度0-360°0为正北
if (typeof res.alpha === 'number' && !isNaN(res.alpha)) {
// 取整数角度,减少抖动
const currentAngle = Math.round(res.alpha);
const now = Date.now();
// 满足以下条件才更新:
// 1. 距离上次更新超过最小间隔时间
// 2. 角度变化超过阈值(首次记录时直接更新)
const isAngleChangedEnough = lastAngle === null ||
Math.abs(currentAngle - lastAngle) >= ANGLE_THRESHOLD;
const isTimeEnough = now - lastUpdateTime >= MIN_UPDATE_INTERVAL;
if (isAngleChangedEnough && isTimeEnough) {
console.log(`方向变化超过${ANGLE_THRESHOLD}度,更新角度: ${currentAngle}`);
this.updateArrowDirection(currentAngle);
// 更新记录值
lastAngle = currentAngle;
lastUpdateTime = now;
}
if (this.data.directonAngle == -1) {
this.setData({
directonAngle: currentAngle
});
this.updateArrowDirection(currentAngle);
}
}
});
},
fail: (err) => {
console.error('监听启动失败:', err);
}
});
},
// 页面隐藏/卸载时停止监听(必须做,否则会耗电)
onHide() {
this.stopListening();
},
onUnload() {
this.stopListening();
},
// 停止监听的工具方法
stopListening() {
if (this.motionListener) {
this.motionListener(); // 移除监听事件
this.motionListener = null;
}
wx.stopDeviceMotionListening({}); // 停止监听服务
},
updateScale() {
const that = this
// 直接获取当前缩放级别(同步操作,无延迟)
this.mapCtx.getScale({
success(res) {
const currentScale = res.scale
// 计算比例尺数值
that.calcScale(currentScale)
},
// 极端情况如果获取失败100ms后重试确保最终能更新
fail() {
setTimeout(() => {
that.updateScale()
}, 100)
}
})
},
calcScale(scale) {
// 计算100px线段对应的实际距离
const metersPerPx = 156543.03392 * Math.cos(39.915 * Math.PI / 180) / Math.pow(2, scale)
const totalMeters = metersPerPx * 100 // 100px线段的实际距离
// ----------------------
// 公制单位:米 → 千米(自动转换+取整)
// ----------------------
let metricText;
if (totalMeters >= 1000) {
// ≥1000米时转千米四舍五入取整数
const km = Math.round(totalMeters / 1000)
metricText = `${km}千米`
} else {
// <1000米时保留米四舍五入取整数
metricText = `${Math.round(totalMeters)}`
}
metricText = metricText
// ----------------------
// 英制单位:英尺 → 英里(自动转换+取整)
// 1英里 = 5280英尺转换临界点
// ----------------------
const totalFeet = totalMeters * 3.28084 // 先转成英尺
let imperialText;
if (totalFeet >= 5280) {
// ≥5280英尺时转英里四舍五入取整数
const miles = Math.round(totalFeet / 5280)
imperialText = `${miles}英里`
} else {
// <5280英尺时保留英尺四舍五入取整数
imperialText = `${Math.round(totalFeet)}英尺`
}
this.setData({
metric: metricText,
imperial: imperialText
})
},
onShow() {
console.log("on-->" + "onShow");
// 同步全局登录状态
this.setData({
isLoggedIn: app.globalData.isLoggedIn,
userInfo: app.globalData.userInfo
});
if (this.data.amapReady) {
this.startLocationService();
}
// 设置tabBar选中状态为"发现"索引0
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({
selected: 0
});
}
if (app.globalData && app.globalData.needOpenLocationFavoriteBar) {
setTimeout(() => {
this.onOpenLocationFavoriteBar();
}, 300);
app.globalData.needOpenLocationFavoriteBar = false;
}
},
onHide() {
this.stopLocationService();
wx.hideLoading();
},
onUnload() {
this.stopLocationService();
},
// 初始化高德地图SDK
initAMapSDK() {
try {
// 使用完整版本的高德地图SDK包含逆地理编码功能
this.amapFun = new AMapWX({
key: config.amapKey || '' // 需要有效的API Key才能使用全部功能
});
this.setData({
amapReady: true,
amapError: null
});
console.debug('✅ 高德地图SDK初始化成功');
} catch (error) {
console.error('❌ 高德地图SDK初始化失败:', error);
this.setData({
amapReady: false,
amapError: error.message || '高德地图SDK初始化失败'
});
wx.showToast({
title: '定位服务异常',
icon: 'none'
});
}
},
// 初始化系统信息
initSystemInfo() {
try {
const systemInfo = this.systemInfoHelper.getSystemInfoSync();
const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
const statusBarHeight = systemInfo.statusBarHeight || 44;
const menuButtonHeight = menuButtonInfo.height || 32;
const menuButtonTop = menuButtonInfo.top || statusBarHeight + 6;
const navBarHeight = statusBarHeight + menuButtonHeight + 10;
this.setData({
statusBarHeight: statusBarHeight,
menuButtonHeight: menuButtonHeight,
navBarHeight: navBarHeight,
windowHeight: systemInfo.windowHeight || 667,
safeAreaBottom: systemInfo.safeArea ? systemInfo.windowHeight - systemInfo.safeArea.bottom : 0
});
} catch (error) {
console.error('获取系统信息失败:', error);
// 设置默认值
this.setData({
statusBarHeight: 44,
menuButtonHeight: 32,
menuButtonTop: 50,
navBarHeight: 88,
windowHeight: 667,
safeAreaBottom: 0
});
}
},
// 请求位置权限
requestLocationPermission() {
// 直接尝试获取位置,如果失败会自动触发权限请求
this.getCurrentLocation();
},
// 获取当前位置 - 双保险定位策略
getCurrentLocation() {
if (!this.data.amapReady) {
this.getWxLocation(); // 降级方案
return;
}
this.amapFun.getWxLocation((location, error) => {
if (error) {
console.error('高德SDK获取位置失败:', error);
this.getWxLocation(); // 降级方案
return;
}
this.processLocationResult(location);
}, {
type: 'gcj02',
isHighAccuracy: true,
highAccuracyExpireTime: 4000
});
},
// 微信原生定位降级方案
getWxLocation() {
wx.getLocation({
type: 'gcj02',
isHighAccuracy: true,
highAccuracyExpireTime: 4000,
success: (location) => {
// 模拟高德地图数据格式,但不直接显示坐标
const enhancedLocation = {
...location,
address: '定位中...', // 使用友好的占位符
formattedAddress: '',
province: '',
city: '',
district: '',
street: ''
};
this.processLocationResult(enhancedLocation);
},
fail: (error) => {
console.error('微信原生定位也失败:', error);
this.handleLocationError(error);
}
});
},
// 🔥 新增:基于坐标的简化位置推断 - 修复版
getLocationByCoordinates(latitude, longitude) {
const lat = parseFloat(latitude);
const lng = parseFloat(longitude);
let province = '';
let city = '';
let district = '';
// 基于经纬度范围的简化位置推断
// 实际项目中可能需要调用专业的地理编码API或后端服务
// 北京地区
if (lat >= 39.4 && lat <= 41.6 && lng >= 115.4 && lng <= 117.5) {
province = '北京';
city = '北京市';
district = '朝阳区';
}
// 上海地区
else if (lat >= 30.6 && lat <= 31.8 && lng >= 121.2 && lng <= 122.1) {
province = '上海';
city = '上海市';
district = '浦东新区';
}
// 广州地区
else if (lat >= 22.5 && lat <= 23.5 && lng >= 112.9 && lng <= 114.3) {
province = '广东';
city = '广州市';
district = '天河区';
}
// 深圳地区
else if (lat >= 22.4 && lat <= 22.8 && lng >= 113.7 && lng <= 114.6) {
province = '广东';
city = '深圳市';
district = '南山区';
}
// 更多城市的判断(可以根据实际需求添加更多城市)
// 杭州地区
else if (lat >= 29.0 && lat <= 30.5 && lng >= 118.0 && lng <= 120.0) {
province = '浙江';
city = '杭州市';
district = '西湖区';
}
// 南京地区
else if (lat >= 31.0 && lat <= 33.0 && lng >= 117.0 && lng <= 119.0) {
province = '江苏';
city = '南京市';
district = '玄武区';
}
// 成都地区
else if (lat >= 30.0 && lat <= 31.5 && lng >= 103.5 && lng <= 104.5) {
province = '四川';
city = '成都市';
district = '锦江区';
}
// 其他地区 - 使用通用位置信息
else {
// 改进:为了更好的用户体验,不再使用'地图'作为默认区域
// 而是根据经纬度范围提供一个更有意义的默认位置
const latInt = Math.round(lat);
const lngInt = Math.round(lng);
// 使用经纬度整数部分作为位置标识,让用户知道这是一个估算的位置
district = `${latInt}°${lngInt}°附近`;
city = '中国';
province = '位置';
}
const address = province && city ? `${province}${city}${district}` : `${district}`;
return {
province,
city,
district,
address
};
},
// 处理位置结果
processLocationResult(location) {
console.log('✅ 获取到经纬度: lat: ' + location.latitude + " long: " + location.longitude);
// 保存自己的位置信息
const myLocation = {
latitude: location.latitude,
longitude: location.longitude,
accuracy: location.accuracy || 0
};
this.setData({
myLocation: myLocation
})
const previousLocation = this.lastLocationSnapshot;
this.lastLocationSnapshot = myLocation;
// 保存位置精度;仅在需要跟随或尚未初始化时更新地图中心
const locationUpdate = {
accuracy: location.accuracy || 0,
myLocation: myLocation
};
const hasInitialCenter = typeof this.data.latitude === 'number' && typeof this.data.longitude === 'number' &&
!Number.isNaN(this.data.latitude) && !Number.isNaN(this.data.longitude) &&
this.data.latitude !== 0 && this.data.longitude !== 0;
if (this.data.shouldFollowLocation || !hasInitialCenter) {
locationUpdate.latitude = location.latitude;
locationUpdate.longitude = location.longitude;
}
this.setData(locationUpdate);
// 创建用户位置标记(带头像和电量信息)
this.createUserMarkers(myLocation);
// 只有在shouldFollowLocation为true时才移动地图
if (this.mapCtx && this.data.shouldFollowLocation) {
try {
this.setData({
shouldFollowLocation: false
});
this.mapCtx.moveToLocation({
latitude: location.latitude,
longitude: location.longitude,
success: () => {
console.debug('✅ 地图移动到当前位置成功');
},
fail: (error) => {
console.error('❌ 地图移动失败:', error);
}
});
} catch (error) {
console.error('❌ 移动地图到当前位置时出现异常:', error);
}
}
// 解析地址 - 使用Promise处理异步结果
this.resolveAddress(location).then(() => {
// 地址解析完成后继续执行其他操作
console.debug('✅ 地址解析完成,继续执行其他操作');
}).catch((error) => {
console.error('⚠️ 地址解析过程中出现错误,但继续执行其他操作:', error);
});
// 加载好友位置
const now = Date.now();
if (!this.lastFriendsFetch || (now - this.lastFriendsFetch) > 45 * 1000) {
this.lastFriendsFetch = now;
if (!this.data.mapFeedVisible && !this.data.isOnline) {
this.loadFriendsLocation();
}
}
// 获取附近用户 - 已启用
if (!this.lastNearbyFetch || (now - this.lastNearbyFetch) > 45 * 1000) {
if (this.data.isOnline && !this.data.mapFeedVisible) {
this.lastNearbyFetch = now;
this.loadNearbyUsers();
}
}
this.scheduleMapFeedRefresh('location');
},
// 创建用户位置标记(带头像和电量信息)
createUserMarkers(myLocation) {
// 安全地获取头像URL处理 userInfo 可能为 null 的情况
let avatarUrl = '/images/default-stranger.png'; // 默认头像
if (app.globalData.userInfo && app.globalData.userInfo.user && app.globalData.userInfo.user.avatar) {
avatarUrl = app.globalData.userInfo.user.avatar;
}
if (avatarUrl.includes('myqcloud')) {
avatarUrl = avatarUrl + '?imageMogr2/auto-orient/thumbnail/100x100/quality/85';
}
console.log("userInfoUrl--->" + avatarUrl);
let userMarkers = [];
const userMarker = {
id: 1,
latitude: myLocation.latitude,
longitude: myLocation.longitude,
iconPath: '/images/map/marker_blank.png',
avatarUrl: avatarUrl ? avatarUrl : '/images/default-stranger.png',
directionPath: '/images/map/direction_arrow.png',
type: 'mine',
directonAngle: this.data.directonAngle,
joinCluster: false,
title: "我",
height: 45,
width: 45,
customCallout: {
anchorX: 0, // 水平锚点设为 0.5(图标宽度的正中间)
anchorY: 70, // 垂直锚点设为 1图标底部紧贴地图坐标点
display: 'ALWAYS'
},
zIndex: 1
}
// this.data.allMarkers.push(userMarker);
const existingIndex = this.data.allMarkers.findIndex(marker => marker.id === 1);
if (existingIndex == -1) {
this.data.allMarkers.push(userMarker);
}
userMarkers.push(userMarker);
this.updateMarkersByMarkersType(userMarkers);
},
// 解析地址 - 多级解析策略
async resolveAddress(location) {
console.log('🏠 处理地址信息location数据:', location);
let address = '未知位置';
let addressDetail = {};
let currentDistrict = '';
let currentCity = '';
let realLocationInfo = {};
// 优先尝试获取真实位置信息(无论登录状态)
try {
realLocationInfo = await this.tryGetRealLocationInfo(location.latitude, location.longitude);
} catch (error) {
console.error('⚠️ 获取真实位置信息失败:', error);
}
if (realLocationInfo) {
address = realLocationInfo.address || address;
currentDistrict = realLocationInfo.district || currentDistrict;
// 不设置currentCity只使用区级信息
console.log('✅ 使用真实位置信息:', {
address,
currentDistrict
});
} else {
// 从高德地图定位结果中获取地址信息
if (location.address && location.address.trim()) {
address = location.address;
console.debug('✅ 使用高德地图返回的地址:', address);
} else if (location.formattedAddress && location.formattedAddress.trim()) {
address = location.formattedAddress;
console.debug('✅ 使用格式化地址:', address);
} else {
// 降级处理:使用坐标作为地址
address = `位置: ${location.latitude.toFixed(6)}, ${location.longitude.toFixed(6)}`;
console.debug('⚠️ 降级使用坐标作为地址:', address);
}
}
// 优先使用SDK返回的结构化地址
if (location.province || location.city || location.district) {
addressDetail = {
province: location.province || '',
city: location.city || '',
district: location.district || '',
street: location.street || '',
streetNumber: location.streetNumber || '',
description: location.description || address
};
currentDistrict = location.district || '';
// 不设置currentCity只使用区级信息
}
// 如果SDK没有返回结构化信息从完整地址字符串中智能解析
if (!currentDistrict && !currentCity && address) {
// 智能解析中国地址格式的正则表达式
const addressPattern = /(.*?)省?(.*?)市?(.*?)区?(.*?)县?(.*?)镇?(.*?)乡?(.*)/;
const match = address.match(addressPattern);
if (match) {
const [, province, city, district] = match;
// 不设置currentCity只使用区级信息
currentDistrict = district;
console.debug('📍 正则解析结果:', {
province,
district: currentDistrict
});
}
}
// 降级处理:如果以上方法都失败,提取地址前几个字符作为区域显示
if (!currentDistrict && !currentCity && address) {
// 最后的降级方案:使用地址的前几个字符
currentDistrict = address.substring(0, 4) || '定位中...';
console.debug('📍 降级使用地址前缀:', currentDistrict);
}
console.debug('📍 最终解析的区域信息:', {
address,
currentDistrict,
currentCity,
locationData: location
});
this.setData({
currentAddress: address,
addressDetail: addressDetail,
currentDistrict: currentDistrict,
currentCity: '' // 不显示城市信息,只显示区级信息
});
if (!this.lastWeatherFetch || (Date.now() - this.lastWeatherFetch) > 30 * 60 * 1000) {
this.lastWeatherFetch = Date.now();
this.loadWeatherInfo(location.latitude, location.longitude);
}
// 更新位置信息到服务器
this.updateLocationToServer({
...location,
address: address,
addressDetail: addressDetail
});
},
// 更新位置到服务器 - 尝试从响应中获取地址信息
async updateLocationToServer(locationData) {
try {
// 🔥 添加登录状态检查
const app = getApp();
const isLoggedIn = app?.globalData?.isLoggedIn || false;
if (!isLoggedIn) {
// 未登录状态下,使用设备直接返回的地址信息(如果有)
if (locationData.address) {
this.setData({
currentDistrict: locationData.address,
locationLoading: false
});
}
return {
success: false,
error: '用户未登录',
skipAuth: true
};
}
const systemInfo = this.systemInfoHelper.getSystemInfoSync();
const updateData = {
latitude: parseFloat(locationData.latitude),
longitude: parseFloat(locationData.longitude),
altitude: parseFloat(locationData.altitude) || 0,
accuracy: parseFloat(locationData.accuracy) || 0,
speed: parseFloat(locationData.speed) || 0,
direction: parseFloat(locationData.direction) || 0,
deviceType: 'miniprogram',
deviceModel: systemInfo.model || 'Unknown',
battery: systemInfo.battery || 100
};
console.log('✅ 上传的经纬度:', ' latitude ' + locationData.latitude + ' longitude ' + locationData.longitude);
const response = await this.apiClient.updateLocation(updateData);
console.log('✅ 位置更新成功,服务器响应:', response);
// 🔥 优化:从服务器响应中获取准确的地址信息
if (response && response.data) {
const serverData = response.data;
// 检查服务器是否返回了地址信息
if (serverData.address || serverData.district || serverData.city || serverData.province) {
// 服务器位置信息是基于坐标查询的,比本地解析更准确
// 对于登录用户,始终优先使用服务器返回的地址信息
if (isLoggedIn) {
const newDistrict = serverData.district || serverData.city || this.data.currentDistrict;
const newAddress = serverData.address || this.data.currentAddress;
this.setData({
// currentDistrict: newDistrict,
currentCity: '', // 不显示城市信息,只使用区级信息
currentAddress: newAddress
});
console.debug('✅ 已使用位置更新接口的地址信息更新左上角显示:', {
district: newDistrict,
address: newAddress
});
}
// 对于未登录用户,如果当前区域信息不准确或缺失,优先使用服务器信息
else if (!this.data.currentDistrict ||
this.data.currentDistrict === '定位中...' ||
this.data.currentDistrict === '位置信息' ||
this.data.currentDistrict.includes('位置 ')) {
const newDistrict = serverData.district || serverData.city || this.data.currentDistrict;
const newAddress = serverData.address || this.data.currentAddress;
this.setData({
// currentDistrict: newDistrict,
currentCity: '', // 不显示城市信息,只使用区级信息
currentAddress: newAddress
});
}
}
}
} catch (error) {
console.error('❌ 位置更新失败:', error);
// 不阻断用户体验,仅记录错误
}
},
// 处理位置错误
handleLocationError(error) {
console.error('位置服务错误:', error);
let errorMessage = '获取位置失败';
if (error.errMsg) {
if (error.errMsg.includes('auth deny')) {
errorMessage = '位置权限被拒绝,请在设置中开启位置权限';
} else if (error.errMsg.includes('timeout')) {
errorMessage = '定位超时,请检查网络连接';
} else if (error.errMsg.includes('locate fail')) {
errorMessage = '定位失败,请稍后重试';
}
}
wx.showToast({
title: errorMessage,
icon: 'none',
duration: 3000
});
// 设置默认位置(如果有的话)
if (this.data.defaultLocation) {
this.setData({
longitude: this.data.defaultLocation.longitude,
latitude: this.data.defaultLocation.latitude,
currentAddress: this.data.defaultLocation.address || '位置获取失败'
});
}
},
// 启动位置更新服务 - 增强版:实时位置更新
startLocationService() {
// 清除旧的定时器
if (this.locationTimer) {
clearInterval(this.locationTimer);
}
// if (!this.data.hasUserInteractedWithMap) {
// this.setData({
// shouldFollowLocation: false
// });
// }
// 立即更新一次位置
if (this.data.amapReady) {
this.getCurrentLocation();
}
const refreshInterval = config?.locationUpdateInterval || 30000;
this.locationTimer = setInterval(() => {
if (this.data.amapReady) {
this.getCurrentLocation();
}
}, refreshInterval);
},
// 停止位置更新服务
stopLocationService() {
if (this.locationTimer) {
clearInterval(this.locationTimer);
this.locationTimer = null;
}
},
// 计算两点之间的距离(米)
calculateDistance(lat1, lng1, lat2, lng2) {
const R = 6371000; // 地球半径(米)
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLng = (lng2 - lng1) * Math.PI / 180;
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
},
// 格式化距离显示
formatDistance(distance) {
if (distance < 1000) {
return Math.round(distance) + 'm';
} else if (distance < 10000) {
return (distance / 1000).toFixed(1) + 'km';
} else {
return Math.round(distance / 1000) + 'km';
}
},
// 加载好友位置
async loadFriendsLocation() {
try {
console.debug('👥 开始加载好友位置');
// const response = await this.apiClient.getFriendsLocation();
const [region, scaleResult] = await Promise.all([
this.getMapRegion(),
this.getMapScale()
]);
let scale = Math.round(scaleResult?.scale || this.data.scale || 13);
const payload = buildBoundsPayload(region);
if (scale > 20) {
scale = 20;
}
const friendsAndStrangerSprams = {
"bounds": payload.bounds,
"zoomLevel": scale,
"displayMode": "friends",
// "maxPoints": 200,
// "clusterThreshold": 100,
// "onlineMode": "all",
"showOffline": true,
"clusterThreshold": this.data.clusterThreshold,
// "genderFilter": 0,
// "ageRangeMin": 18,
// "ageRangeMax": 35,
// "memberOnly": false,
// "enableRealTimeUpdate": false,
// "currentLat": this.data.myLocation.latitude,
// "currentLng": this.data.myLocation.longitude
}
let response = await this.apiClient.getFriendsAndStranger(friendsAndStrangerSprams);
// 处理API响应数据结构
if (response && response.code === 0 && response.data) {
if (!this.data.mapFeedVisible && !this.data.isOnline) {
// if (scale > 8) {
// response = mockResponseFriend
// } else {
// response = mockResponseFriendMarkerCluster;
// }
this.addFriendsMarkersByResult(response.data);
this.setData({
friendsData: response.data.userPoints
});
}
// 只保存数据不直接操作markers数组
// this.setData({
// friendsData: friendsLocation,
// friendsCount: friendsLocation.length
// });
// 调用统一的标记管理函数来更新地图标记
} else {
console.debug('📍 暂无好友位置信息');
this.setData({
friendsCount: 0,
friendsData: []
});
// 调用统一的标记管理函数来更新地图标记
}
} catch (error) {
console.error('❌ 加载好友位置失败:', error);
// this.setData({
// friendsCount: 0,
// friendsData: []
// });
// 调用统一的标记管理函数来更新地图标记
// 只对已登录用户显示友好的错误提示
const app = getApp();
const isLoggedIn = app?.globalData?.isLoggedIn || false;
// if (isLoggedIn && error.message && !error.message.includes('401')) {
// wx.showToast({
// title: '好友位置加载失败',
// icon: 'none',
// duration: 2000
// });
// }
}
},
// 回到自己位置 - 定位按钮功能
centerToUserLocation() {
if (!this.data.myLocation) {
this.getCurrentLocation();
return;
}
// 设置为跟随用户位置,并重置交互标记
this.setData({
shouldFollowLocation: false,
hasUserInteractedWithMap: false
});
// 移动地图到自己的位置
this.mapCtx.moveToLocation({
latitude: this.data.myLocation.latitude,
longitude: this.data.myLocation.longitude
});
// 重置缩放级别到合适的级别
this.setData({
latitude: this.data.myLocation.latitude,
longitude: this.data.myLocation.longitude,
currentMapScale: 16
});
// 获取地图上下文(关键:确保能拿到实时缩放级别)
this.mapCtx = wx.createMapContext('main-map')
// 初始化计算
let that = this;
setTimeout(() => {
that.updateScale()
}, 1000)
},
//收藏地址
async onPoiFavoriteCommon(address, latitude, longitude, name) {
wx.request({
url: `${config.api.baseUrl}/api/v1/location/place-mark`,
method: 'POST',
data: JSON.stringify({
"name": name,
"category": "home", // "home" | "work" | "favorite" | "other"
"icon": "home_icon",
"latitude": latitude,
"longitude": longitude,
"address": address,
"description": "温馨的家",
"isPrivate": true,
"reminder": false
}),
header: {
'Authorization': `Bearer ${apiClient.getToken()}`,
'Content-Type': 'application/json',
},
success: (res) => {
if (res.data.code === 0) {
this.setData({
placeMarkId: res.data.data.placeMarkId,
mapClickCollect: '取消收藏'
});
wx.showToast({
title: '已收藏',
icon: 'success'
});
} else {
wx.showToast({
title: '收藏失败',
icon: 'success'
});
}
},
fail: () => {
wx.showToast({
title: '收藏失败,请重试',
icon: 'none'
});
}
});
},
//取消收藏
async onPoiCancelCommon(placeMarkId) {
wx.request({
url: `${config.api.baseUrl}/api/v1/location/place-mark/${placeMarkId}`,
method: 'DELETE',
header: {
'Authorization': `Bearer ${apiClient.getToken()}`,
'Content-Type': 'application/json',
},
success: (res) => {
if (res.data.code === 0) {
this.setData({
placeMarkId: "",
mapClickCollect: "收藏"
});
wx.showToast({
title: '取消收藏成功',
icon: 'success'
});
} else {
wx.showToast({
title: '取消收藏失败',
icon: 'success'
});
}
},
fail: () => {
wx.showToast({
title: '取消收藏失败,请重试',
icon: 'none'
});
}
});
},
//收藏地址
async onPoiFavorite(e) {
const address = e.currentTarget.dataset.poidetail.address;
const latitude = e.currentTarget.dataset.poidetail.latitude;
const longitude = e.currentTarget.dataset.poidetail.longitude;
const name = e.currentTarget.dataset.poidetail.name;
if (this.data.placeMarkId == '') { //空 说明还没有收藏地址
this.onPoiFavoriteCommon(address, latitude, longitude, name);
} else { //说明刚才收藏了 再点击就是取消
this.onPoiCancelCommon(this.data.placeMarkId);
}
},
// 地图区域变化完成事件
onMapRegionChange(e) {
// 无论缩放开始/进行中/结束,都强制更新(确保不遗漏)
console.log("地图移动---->" + e.detail);
// this.addDynamicMarkersByResult(mockResponseDynamic.data);
const type = e.causedBy;
if (type === 'scale') { //放大缩小
this.updateScale()
}
const detail = e.detail || {};
const changeType = e.type || 'unknown';
// if (detail.causedBy !== 'update') {
// }
// 当地图被手动拖动时,停止跟随用户位置
if (changeType === 'end' && (detail.causedBy === 'drag' || detail.causedBy === 'scale')) {
this.setData({
shouldFollowLocation: false,
hasUserInteractedWithMap: true
});
}
// 只在拖拽结束时处理,避免频繁触发
if (changeType === 'end' && detail.scale) {
setTimeout(() => {
const currentScale = Math.round(detail.scale);
// this.setData({
// currentMapScale: currentScale
// });
if (this.mapCtx && this.data.myLocation) {
try {
// 更新用户标记的位置
// this.data.userMarker.latitude = this.data.myLocation.latitude;
// this.data.userMarker.longitude = this.data.myLocation.longitude;
if (this.data.isOnline && !this.data.mapFeedVisible) {
this.loadNearbyUsers();
}
if (!this.data.mapFeedVisible && !this.data.isOnline) {
this.loadFriendsLocation();
}
if (this.data.mapFeedVisible) {
this.scheduleMapFeedRefresh('location');
}
} catch (error) {
console.error('⚠️ 地图区域变化后更新标记失败:', error);
}
}
}, 300);
const isUserGesture = detail.causedBy === 'drag' || detail.causedBy === 'scale';
if (isUserGesture) {
// this.scheduleMapFeedRefresh('region-change');
}
}
},
// 地图点击事件 - 显示点击位置的POI资料卡
onMapTap(e) {
// 点击地图时关闭用户详情卡片
this.closeUserCard();
this.hideFeedBubble();
// 获取点击位置的经纬度
if (e && e.detail && e.detail.latitude && e.detail.longitude) {
// 相机移动到点击位置
if (this.data.shouldFollowLocation) {
this.mapCtx && this.mapCtx.moveToLocation({
latitude: e.detail.latitude,
longitude: e.detail.longitude
});
}
}
},
// 地图长按事件
onMapLongTap(e) {
// 只有在动态模式下才显示发布动态选项
if (this.data.isOnline) {
// 保存当前长按位置
const location = {
latitude: e.detail.latitude,
longitude: e.detail.longitude
};
this.setData({
currentDynamicLocation: location,
showDynamicInputModal: true,
dynamicContent: ''
});
}
// else {
// wx.showToast({
// title: e && e.detail && e.detail.latitude && e.detail.longitude ?
// `长按:${e.detail.latitude.toFixed(6)},${e.detail.longitude.toFixed(6)}` :
// '长按地图操作',
// icon: 'none'
// });
// }
},
// 关闭动态输入弹窗
closeDynamicInputModal() {
this.setData({
showDynamicInputModal: false,
dynamicContent: ''
});
},
// 输入动态内容
onDynamicContentInput(e) {
this.setData({
dynamicContent: e.detail.value
});
},
// 发布动态
publishDynamic() {
const {
dynamicContent,
currentDynamicLocation
} = this.data;
if (!dynamicContent.trim()) {
wx.showToast({
title: '动态内容不能为空',
icon: 'none'
});
return;
}
if (!currentDynamicLocation) {
wx.showToast({
title: '位置信息无效',
icon: 'none'
});
return;
}
// 创建新动态
const newDynamic = {
id: Date.now(), // 使用时间戳作为唯一ID
content: dynamicContent.trim(),
latitude: currentDynamicLocation.latitude,
longitude: currentDynamicLocation.longitude,
creator: this.data.userInfo?.nickname || '匿名用户',
avatar: this.data.userInfo?.avatarUrl || '',
createTime: new Date().toISOString(),
likes: 0,
comments: []
};
// 添加到动态列表
const updatedDynamics = [...this.data.locationDynamics, newDynamic];
this.setData({
locationDynamics: updatedDynamics,
showDynamicInputModal: false,
dynamicContent: ''
});
wx.showToast({
title: '动态发布成功',
icon: 'success'
});
},
// 点击动态标记
onDynamicMarkerTap(e) {
const markerId = e.detail.markerId;
// 查找对应的动态
const dynamic = this.data.locationDynamics.find(d => d.id === markerId);
if (dynamic) {
this.setData({
selectedDynamic: dynamic,
showDynamicDetailModal: true
});
}
},
// 关闭动态详情弹窗
closeDynamicDetailModal() {
this.setData({
showDynamicDetailModal: false,
selectedDynamic: null
});
},
onMarkerTap(e) {
const markerId = e.detail.markerId || e.markerId;
if (markerId === 1) {
// 点击的是用户自己的位置
return;
}
const markers = this.data.markers || [];
const clickedMarker = markers.find(marker => String(marker.id) === String(markerId));
const markerType = clickedMarker?.type || '';
// if (markerType === 'map-feed-cluster') {
// this.setData({
// currentMapScale:18
// })
// this.toLocationByScale(18, clickedMarker.latitude, clickedMarker.longitude);
// return;
// }
if (markerType === 'stranger-cluster' || markerType === 'friend-cluster') {
this.setData({
currentMapScale: 18
})
this.toLocationByScale(18, clickedMarker.latitude, clickedMarker.longitude);
return;
}
if (markerType.startsWith('map-feed')) {
this.handleMapFeedMarkerTap(clickedMarker);
return;
}
if (markerType === 'staticData') {
this.hideFeedBubble();
wx.showModal({
title: clickedMarker?.title || '位置提示',
content: clickedMarker?.description || '暂无更多信息',
showCancel: false,
confirmText: '我知道了'
});
return;
}
if (markerType === 'merchant') {
this.hideFeedBubble();
const merchantId = clickedMarker?.merchantId || (markerId >= 10000 ? markerId - 10000 : null);
const merchant = this.data.merchantList?.find(m => m.id === merchantId);
if (merchant) {
this.setData({
selectedMerchant: merchant,
merchantInfoModalVisible: true,
activeMerchantId: merchantId
});
// 更新markers中的active状态
this.updateMerchantActiveState(merchantId);
}
return;
}
if (markerType === 'dynamic') {
this.hideFeedBubble();
const dynamic = this.data.locationDynamics.find(d => d.id === markerId);
if (dynamic) {
this.setData({
selectedDynamic: dynamic,
showDynamicDetailModal: true
});
}
return;
}
if (markerType == 'friend-single') {
// 计算距离
const myLocation = this.data.myLocation;
const distance = myLocation ? this.calculateDistance(
myLocation.latitude, myLocation.longitude,
clickedMarker.latitude, clickedMarker.longitude
) : 0;
this.setData({
selectedUser: {
...clickedMarker,
distance: distance > 0 ? this.formatDistance(distance) : '',
userId: clickedMarker.customId || clickedMarker.userId,
nickname: clickedMarker.nickname,
avatarUrl: clickedMarker.avatarUrl,
originAvatarUrl:clickedMarker.originAvatarUrl,
isFriend: true
}
});
this.hideFeedBubble();
return;
}
if (markerType == 'stranger-single') {
if (clickedMarker) {
// 计算距离
const myLocation = this.data.myLocation;
const distance = myLocation ? this.calculateDistance(
myLocation.latitude, myLocation.longitude,
clickedMarker.latitude, clickedMarker.longitude
) : 0;
this.setData({
selectedUser: {
...clickedMarker,
distance: distance > 0 ? this.formatDistance(distance) : '',
userId: clickedMarker.customId || clickedMarker.userId,
avatarUrl: clickedMarker.avatarUrl,
nickname: clickedMarker.nickname,
originAvatarUrl:clickedMarker.originAvatarUrl,
isFriend: false
}
});
this.hideFeedBubble();
return;
}
}
},
toggleLike(){
wx.showToast({
title: '点赞成功',
icon: 'none'
});
},
// 地图POI点击事件
onPoiTap(e) {
console.log('📍 POI点击事件:', e.detail);
let that = this;
const poi = {
name: e.detail.name,
address: '',
latitude: e.detail.latitude,
longitude: e.detail.longitude
};
that.setData({
poiDetail: poi,
renderKey: Date.now()
})
this.tryGetRealLocationInfo(e.detail.latitude, e.detail.longitude).then((realLocationInfo) => {
if (realLocationInfo) {
// 先重置数据,再重新赋值
this.setData({
poiDetailAddress: realLocationInfo.address, // 先清空
poiDetailShow: true,
renderKey: Date.now()
});
}
});
that.mapCtx && that.mapCtx.moveToLocation({
latitude: poi.latitude,
longitude: poi.longitude,
success: () => {
// 地图移动完成后再设置数据,确保视图同步
that.setData({
latitude: poi.latitude,
longitude: poi.longitude,
currentMapScale: 17
});
}
});
// 获取地图上下文(关键:确保能拿到实时缩放级别)
that.mapCtx = wx.createMapContext('main-map')
setTimeout(() => {
that.updateScale()
}, 1000)
that.setData({
poiDetailShow: true
});
},
toLocationByScale(scale, lat, lon) {
let that = this;
this.mapCtx && this.mapCtx.moveToLocation({
latitude: lat,
longitude: lon,
success: () => {
// 地图移动完成后再设置数据,确保视图同步
that.setData({
latitude: lat,
longitude: lon
});
if (scale != -1) {
setTimeout(() => {
that.updateScale()
}, 1000)
}
}
});
},
// 关闭POI详情卡片
closePoiCard() {
this.setData({
poiDetail: null,
poiDetailShow: false,
placeMarkId: '',
mapClickCollect: '收藏'
});
},
// POI操作导航
onPoiNavigate() {
const poi = this.data.poiDetail;
if (!poi) {
wx.showToast({
title: '无POI信息',
icon: 'none'
});
return;
}
wx.openLocation({
latitude: poi.latitude,
longitude: poi.longitude,
name: poi.name || '目标位置',
address: poi.address || '',
scale: 16
});
},
// POI操作提醒
onPoiRemind() {
// 关闭POI弹窗打开提醒弹窗初始化范围、好友、模式
const poi = this.data.poiDetail;
this.setData({
showPoiRemindModal: true,
poiRemindRadius: 300,
poiRemindSelectedFriends: [],
poiRemindMode: ['arrive'], // 多选
showFriendSelectModal: false,
lastPoiForRemind: poi
});
this.updatePoiRemindCircle(300);
if (poi) {
this.fitMapToCircle(poi.latitude, poi.longitude, 300);
}
},
// 到达/离开提醒多选切换
onPoiRemindModeChange(e) {
let values = e.detail.value;
if (!Array.isArray(values)) {
values = values ? [values] : [];
}
// 至少保留一个选项,若全取消则默认到达
if (values.length === 0) {
values = ['arrive'];
}
this.setData({
poiRemindMode: values
});
},
// 切换好友选中状态
onToggleFriendSelect(e) {
const userId = e.currentTarget.dataset.userid;
// 选满且未选中的不能再点
if (this.data.poiRemindSelectedFriends.length >= 3 && !this.isFriendSelected(userId)) return;
let selected = this.data.poiRemindSelectedFriends.slice();
const idx = selected.findIndex(f => f.userId === userId);
if (idx > -1) {
selected.splice(idx, 1);
} else {
if (selected.length >= 3) {
wx.showToast({
title: '最多选择3位好友',
icon: 'none'
});
return;
}
const friend = this.data.allFriendsList.find(f => f.userId === userId);
if (friend) selected.push(friend);
}
// 更新filteredFriendsList的selected字段
const selectedIds = selected.map(f => f.userId);
const filteredFriendsList = this.data.filteredFriendsList.map(f => ({
...f,
selected: selectedIds.includes(f.userId)
}));
this.setData({
poiRemindSelectedFriends: selected,
filteredFriendsList
});
},
// 判断某个好友是否已被选中
isFriendSelected(userId) {
return this.data.poiRemindSelectedFriends.some(f => f.userId === userId);
},
// 完成好友选择,关闭弹窗
onFriendSelectDone() {
this.setData({
showFriendSelectModal: false
});
},
// 关闭弹窗
onCloseFriendSelect() {
this.setData({
showFriendSelectModal: false
});
},
// 移除已选好友
onRemoveSelectedFriend(e) {
const userId = e.currentTarget.dataset.userid;
let selected = this.data.poiRemindSelectedFriends.slice();
const idx = selected.findIndex(f => f.userId === userId);
if (idx > -1) {
selected.splice(idx, 1);
// 更新filteredFriendsList的selected字段
const selectedIds = selected.map(f => f.userId);
const filteredFriendsList = this.data.filteredFriendsList.map(f => ({
...f,
selected: selectedIds.includes(f.userId)
}));
this.setData({
poiRemindSelectedFriends: selected,
filteredFriendsList
});
}
},
// 关闭提醒弹窗
closePoiRemindModal() {
this.setData({
showPoiRemindModal: false
});
this.updatePoiRemindCircle(0); // 隐藏圆圈
},
// 拖动滑动条时更新范围和圆圈
onPoiRemindRadiusChange(e) {
const radius = Number(e.detail.value);
this.setData({
poiRemindRadius: radius
});
this.updatePoiRemindCircle(radius);
// 地图相机包含提醒范围自适应padding
const poi = this.data.lastPoiForRemind;
if (poi) {
this.fitMapToCircle(poi.latitude, poi.longitude, radius);
}
},
// 更新地图上的圆圈覆盖物
updatePoiRemindCircle(radius) {
const poi = this.data.poiDetail || this.data.lastPoiForRemind;
if (!poi || !radius) {
this.setData({
circles: []
});
return;
}
this.setData({
circles: [{
latitude: poi.latitude,
longitude: poi.longitude,
color: '#667eea88',
fillColor: '#667eea22',
radius: radius,
strokeWidth: 2
}],
lastPoiForRemind: poi
});
},
// 刷新数据
onRefresh() {
wx.showToast({
title: '刷新中...',
icon: 'loading',
duration: 1000
});
// 重新获取位置和好友数据
this.getCurrentLocation();
// 如果已有位置信息,直接刷新其他数据
if (this.data.myLocation) {
this.loadWeatherInfo(this.data.myLocation.latitude, this.data.myLocation.longitude);
}
},
// 关闭用户详情卡片
closeUserCard() {
this.setData({
selectedUser: null
});
},
// 开始聊天
startChat(e) {
const userId = e.currentTarget.dataset.userid;
const niackName = e.currentTarget.dataset.nickname;
// 获取当前用户信息
const userInfo = this.data.userInfo;
if (!userInfo) {
wx.showToast({
title: '用户信息错误',
icon: 'none'
});
return;
}
// 获取当前用户ID
const currentUserId = userInfo.user?.customId || userInfo.customId || '';
if (!currentUserId) {
wx.showToast({
title: '用户ID错误',
icon: 'none'
});
return;
}
// 构建会话ID单聊格式
// 🔥 修复不传递conversationId让聊天页面从API获取正确的会话ID
// 跳转到聊天页面,使用正确的路径和参数格式
wx.navigateTo({
url: `/pages/message/chat/chat?targetId=${userId}&name=${encodeURIComponent(niackName)}&chatType=0&sendMessage=${this.data.merchant}`
});
},
// 添加好友
addFriend(e) {
const userId = e.currentTarget.dataset.userid;
// 实现添加好友逻辑
wx.showModal({
title: '添加好友',
content: '确定要添加这位用户为好友吗?',
success: (res) => {
if (res.confirm) {
// 调用添加好友API
this.performAddFriend(userId);
}
}
});
},
// 执行添加好友
async performAddFriend(userId) {
try {
const response = await this.apiClient.addFriend(userId, '通过地图添加');
if (response.code === 0) {
wx.showToast({
title: '好友请求已发送',
icon: 'success'
});
this.closeUserCard();
} else {
throw new Error(response.message || '添加好友失败');
}
} catch (error) {
console.error('添加好友失败:', error);
wx.showToast({
title: error.message || '添加好友失败',
icon: 'none'
});
}
},
// 查看用户资料
viewProfile(e) {
const userId = e.currentTarget.dataset.userid;
// 跳转到用户资料页面
wx.navigateTo({
url: `/pages/user-profile/user-profile?userId=${userId}`
});
},
// 获取天气信息
async loadWeatherInfo(latitude, longitude) {
try {
// 🔥 优化优先使用第三方API获取天气信息不依赖登录状态
console.debug('🌤️ 开始获取天气信息');
// 1. 首先尝试通过腾讯地图API直接获取真实天气信息
let weatherData = await this.tryGetRealWeatherInfo(latitude, longitude);
// 2. 如果第三方API获取失败再尝试调用服务器天气API
if (!weatherData) {
const response = await this.apiClient.getWeatherInfo(latitude, longitude);
if (response && response.code === 0 && response.data) {
weatherData = response.data;
} else {
}
}
if (weatherData) {
// 转换天气图标
const weatherIcon = this.getWeatherIcon(weatherData.weather, weatherData.icon);
// 判断是否为云彩图标
const isCloudIcon = this.isCloudWeatherIcon(weatherData.weather, weatherData.icon, weatherIcon);
const weatherInfo = {
temperature: Math.round(weatherData.temperature),
weather: weatherData.weather,
icon: weatherIcon,
isCloudIcon: isCloudIcon,
humidity: weatherData.humidity,
windSpeed: weatherData.windSpeed,
windDir: weatherData.windDir,
aqi: weatherData.aqi,
city: '', // 不显示城市信息,只使用区级信息
updateTime: weatherData.updateTime
};
// 🔥 重要修复:使用天气接口返回的准确位置信息更新左上角显示
if (weatherData.city) {
// 天气接口返回的城市信息是最准确的(基于坐标查询的)
// 优先使用天气接口的位置信息更新左上角显示
let newDistrict = this.data.currentDistrict;
// 如果当前区域信息不准确或缺失,使用天气接口的城市信息
if (!this.data.currentDistrict ||
this.data.currentDistrict === '定位中...' ||
this.data.currentDistrict === '位置信息' ||
this.data.currentDistrict.includes('位置 ')) {
newDistrict = weatherData.city;
}
// 更新区域显示信息
this.setData({
currentCity: '', // 不显示城市信息,只使用区级信息
// currentDistrict: newDistrict,
weatherInfo: weatherInfo
});
} else {
// 没有城市信息时,只更新天气信息
this.setData({
weatherInfo: weatherInfo
});
}
console.debug('✅ 天气信息获取成功:', weatherInfo);
} else {
// 提供默认天气信息
await this.provideDefaultWeatherInfo(latitude, longitude);
}
} catch (error) {
console.error('❌ 获取天气信息失败:', error);
// 🔥 新增:提供默认天气信息,确保用户始终能看到天气数据
await this.provideDefaultWeatherInfo(latitude, longitude);
}
},
// 提供默认天气信息
async provideDefaultWeatherInfo(latitude, longitude) {
// 尝试获取真实天气信息
let defaultWeatherInfo = null;
try {
// 尝试使用腾讯地图API的天气服务获取真实天气数据
const weatherResponse = await new Promise((resolve, reject) => {
wx.request({
url: 'https://apis.map.qq.com/ws/weather/v1/',
data: {
location: `${latitude},${longitude}`,
key: 'OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77'
},
success: resolve,
fail: reject
});
});
// 处理天气API响应
if (weatherResponse && weatherResponse.data && weatherResponse.data.status === 0 && weatherResponse.data.result) {
const weatherData = weatherResponse.data.result;
const currentWeather = weatherData.weather[0];
// 构建真实天气信息
defaultWeatherInfo = {
temperature: parseInt(currentWeather.temp, 10),
weather: currentWeather.weather,
icon: this.getWeatherIcon(currentWeather.weather, ''),
isCloudIcon: this.isCloudWeatherIcon(currentWeather.weather, '', ''),
humidity: currentWeather.humidity,
windSpeed: currentWeather.wind.degree,
windDir: currentWeather.wind.direction,
aqi: weatherData.aqi, // 空气质量指数
city: '', // 不显示城市信息,只使用区级信息
updateTime: new Date().toLocaleTimeString()
};
console.debug('✅ 成功获取真实天气信息:', defaultWeatherInfo);
} else {
console.warn('⚠️ 腾讯地图天气API返回数据异常');
}
} catch (error) {
console.error('❌ 获取真实天气信息失败:', error);
}
// 如果无法获取真实天气信息,才使用随机数据作为备选
if (!defaultWeatherInfo) {
const randomTemp = Math.floor(Math.random() * 20) + 15; // 15-35度
const randomHumidity = Math.floor(Math.random() * 40) + 40; // 40-80%
const randomWindSpeed = Math.floor(Math.random() * 10) + 1; // 1-11级
const weatherConditions = ['晴', '多云', '阴', '小雨', '中雨', '大雨'];
const randomWeather = weatherConditions[Math.floor(Math.random() * weatherConditions.length)];
// 获取天气图标
const weatherIcon = this.getWeatherIcon(randomWeather, '');
const isCloudIcon = this.isCloudWeatherIcon(randomWeather, '', weatherIcon);
// 构建默认天气信息
defaultWeatherInfo = {
temperature: randomTemp,
weather: randomWeather,
icon: weatherIcon,
isCloudIcon: isCloudIcon,
humidity: randomHumidity,
windSpeed: randomWindSpeed,
windDir: '东北风',
aqi: 60,
city: '', // 不显示城市信息,只使用区级信息
updateTime: new Date().toLocaleTimeString()
};
}
// 确保区域信息不为空
let districtToShow = this.data.currentDistrict;
// 先设置一个默认的占位文本,避免显示坐标
if (!districtToShow ||
districtToShow === '定位中...' ||
districtToShow.includes('位置 ') ||
districtToShow === '地图' ||
districtToShow === '默认') {
// 立即设置一个友好的占位符,避免显示坐标
this.setData({
currentDistrict: '定位中...'
});
}
// 尝试通过API获取真实的地址信息无论是否登录
this.tryGetRealLocationInfo(latitude, longitude).then((realLocationInfo) => {
if (realLocationInfo && realLocationInfo.city) {
console.debug('✅ 成功获取真实地址信息:', realLocationInfo);
districtToShow = realLocationInfo.district || realLocationInfo.city;
} else {
// 如果区域信息仍为空,使用坐标推断的位置
if (!districtToShow ||
districtToShow === '定位中...' ||
districtToShow.includes('位置 ') ||
districtToShow === '地图' ||
districtToShow === '默认') {
// 或者尝试其他方式获取位置信息
districtToShow = '北京市';
}
}
// 先设置天气信息
this.setData({
weatherInfo: defaultWeatherInfo
});
// 对于登录用户,保留从服务器获取的真实地址信息
// 直接从全局获取登录状态,避免页面数据同步不及时的问题
const app = getApp();
const isLoggedIn = app?.globalData?.isLoggedIn || false;
if (isLoggedIn && this.data.currentDistrict &&
this.data.currentDistrict !== '定位中...' &&
!this.data.currentDistrict.includes('位置 ') &&
this.data.currentDistrict !== '地图' &&
this.data.currentDistrict !== '默认') {
console.debug('✅ 登录用户,保留服务器返回的真实地址信息:', this.data.currentDistrict);
return;
}
// 更新数据
this.setData({
currentCity: '' // 不显示城市信息,只显示区级信息
// currentDistrict: districtToShow
});
console.debug('✅ 默认天气信息已提供:', defaultWeatherInfo);
}).catch((error) => {
console.error('❌ 获取真实地址信息失败:', error);
// 如果区域信息仍为空,使用坐标推断的位置
if (!districtToShow ||
districtToShow === '定位中...' ||
districtToShow.includes('位置 ') ||
districtToShow === '地图' ||
districtToShow === '默认') {
// 使用更具体的默认位置
districtToShow = '北京市';
// 不设置城市信息,只使用区级信息
defaultWeatherInfo.city = '';
}
// 先设置天气信息
this.setData({
weatherInfo: defaultWeatherInfo
});
// 对于登录用户,保留从服务器获取的真实地址信息
// 直接从全局获取登录状态,避免页面数据同步不及时的问题
const app = getApp();
const isLoggedIn = app?.globalData?.isLoggedIn || false;
if (isLoggedIn && this.data.currentDistrict &&
this.data.currentDistrict !== '定位中...' &&
!this.data.currentDistrict.includes('位置 ') &&
this.data.currentDistrict !== '地图' &&
this.data.currentDistrict !== '默认') {
console.debug('✅ 登录用户,保留服务器返回的真实地址信息:', this.data.currentDistrict);
return;
}
// 更新数据
this.setData({
currentCity: '', // 不显示城市信息,只使用区级信息
// currentDistrict: districtToShow
});
});
},
async tryGetRealWeatherInfo(latitude, longitude) {
return null;
},
// 尝试获取真实的位置信息
tryGetRealLocationInfo(latitude, longitude) {
return new Promise((resolve, reject) => {
const key = config.amapKey; // 注意需单独申请Web服务Key与小程序Key不同
wx.request({
url: baseAmapUrl + `/geocode/regeo`,
data: {
location: `${longitude},${latitude}`,
key: key,
radius: 1000
},
success: (res) => {
if (res.data.status === '1') {
const addressComponent = res.data.regeocode.addressComponent;
const locationInfo = {
province: addressComponent.province || '',
city: addressComponent.city || '',
district: addressComponent.district || '',
address: res.data.regeocode.formatted_address || ''
};
resolve(locationInfo);
} else {
reject(new Error('解析失败:' + res.data.info));
}
},
fail: reject
});
});
},
// 根据天气状况获取对应的表情符号
getWeatherIcon(weather, iconCode) {
// 天气图标映射
const weatherIcons = {
'晴': '☀️',
'多云': '⛅',
'阴': '☁️',
'小雨': '🌦️',
'中雨': '🌧️',
'大雨': '⛈️',
'雷雨': '⛈️',
'雪': '❄️',
'小雪': '🌨️',
'大雪': '❄️',
'雾': '🌫️',
'霾': '😷',
'沙尘': '🌪️'
};
// 根据iconCode映射
const iconMapping = {
'clear-day': '☀️',
'clear-night': '🌙',
'partly-cloudy-day': '⛅',
'partly-cloudy-night': '☁️',
'cloudy': '☁️',
'rain': '🌧️',
'sleet': '🌨️',
'snow': '❄️',
'wind': '💨',
'fog': '🌫️'
};
let finalIcon = '🌤️';
// 优先使用iconCode映射其次使用天气描述映射
if (iconCode && iconMapping[iconCode]) {
finalIcon = iconMapping[iconCode];
} else if (weather && weatherIcons[weather]) {
finalIcon = weatherIcons[weather];
}
return finalIcon;
},
// 判断是否为云彩相关图标(需要变成黑色)
isCloudWeatherIcon(weather, iconCode, icon) {
// 云彩相关的天气状况
const cloudWeatherTypes = ['多云', '阴', '雾', '霾'];
// 云彩相关的iconCode
const cloudIconCodes = ['partly-cloudy-day', 'partly-cloudy-night', 'cloudy', 'fog'];
// 云彩相关的emoji
const cloudEmojis = ['⛅', '☁️', '🌫️'];
// 检查各种条件
if (weather && cloudWeatherTypes.includes(weather)) {
return true;
}
if (iconCode && cloudIconCodes.includes(iconCode)) {
return true;
}
if (icon && cloudEmojis.includes(icon)) {
return true;
}
return false;
},
// 获取附近陌生人用户(新增功能)
async loadNearbyUsers() {
try {
const myLocation = this.data.myLocation;
if (!myLocation) {
return;
}
console.debug('👥 开始获取附近用户');
const [region, scaleResult] = await Promise.all([
this.getMapRegion(),
this.getMapScale()
]);
let scale = Math.round(scaleResult?.scale || this.data.scale || 13);
const payload = buildBoundsPayload(region);
if (scale > 20) {
scale = 20;
}
const friendsAndStrangerSprams = {
"bounds": payload.bounds,
"onlineMode": "all",
"zoomLevel": scale,
"displayMode": "strangers",
// "maxPoints": 200,
"clusterThreshold": this.data.clusterThreshold,
// "onlineMode": "all",
// "showOffline": true,
// "genderFilter": 0,
// "ageRangeMin": 18,
// "ageRangeMax": 35,
// "memberOnly": false,
// "enableRealTimeUpdate": false,
"currentLat": this.data.myLocation.latitude,
"currentLng": this.data.myLocation.longitude
}
let response = await this.apiClient.getFriendsAndStranger(friendsAndStrangerSprams);
if (response && response.code === 0 && response.data) {
if (this.data.isOnline && !this.data.mapFeedVisible) {
this.addStrangerMarkersByResult(response.data);
}
} else {
console.debug('📍 暂无附近用户');
this.nearbyUsersData = [];
this.setData({
strangersCount: 0
});
if (this.data.isOnline) {
// this.addStrangerMarkersData();
}
}
} catch (error) {
console.error('❌ 获取附近用户失败:', error);
this.nearbyUsersData = [];
this.setData({
strangersCount: 0
});
if (this.data.isOnline) {
// this.addStrangerMarkersData();
}
}
},
//添加陌生人数据
addStrangerMarkersByResult(responseStranger) {
const userPoints = responseStranger.userPoints || [];
const clusters = responseStranger.clusters || [];
this.clearMarkersByType("stranger-cluster");
this.clearMarkersByType("stranger-single");
const strangerMarkers = userPoints.map((stranger, index) => {
// 为每个标记生成唯一id和随机经纬度偏移
console.log("responseStranger--->single" + "lat--->" + stranger.latitude + "long--->" + stranger.longitude);
let avatarUrl = '/images/default-stranger.png';
if (stranger.avatar) {
if (stranger.avatar.includes('myqcloud')) {
avatarUrl = stranger.avatar + '?imageMogr2/auto-orient/thumbnail/100x100/quality/85';
} else {
avatarUrl = stranger.avatar
}
}
const marker = {
id: MAP_FEED_MARKER_STRANGER_ID + index,
// 基于基础坐标添加随机偏移(确保经纬度不同)
latitude: stranger.latitude,
longitude: stranger.longitude,
iconPath: marker_blank,
type: 'stranger-single',
customId: stranger.customId,
clusterColor: '#FF0000',
avatarUrl: avatarUrl,
originAvatarUrl: stranger.avatar,
merchantType: '',
isOnline: stranger.isOnline,
nickname: stranger.nickname, // 昵称加索引区分
battery: 100,
width: 45,
height: 45,
radius: 380,
joinCluster: false,
title: stranger.nickname,
customCallout: {
anchorY: 50,
anchorX: 0,
display: 'ALWAYS'
},
};
return marker;
});
this.updateMarkersByMarkersType(strangerMarkers);
const strangerClusterMarkers = clusters.map((stranger, index) => {
console.log("responseStranger--->cluster" + "lat--->" + stranger.latitude + "long--->" + stranger.longitude);
const marker = {
// id: stranger.customId,
id: MAP_FEED_CLUSTER_STRANGER_ID + index,
latitude: stranger.latitude,
longitude: stranger.longitude,
iconPath: marker_blank,
feedCount: stranger.onlineCount,
customId: stranger.clusterId,
type: 'stranger-cluster',
badgeColor: MAP_FEED_MARKER_STYLE.stranger.background,
badgeTextColor: MAP_FEED_MARKER_STYLE.stranger.color,
battery: 100,
customCallout: {
anchorY: 50,
anchorX: 0,
display: 'ALWAYS'
},
radius: 380,
width: 45,
height: 45,
};
return marker;
});
this.updateMarkersByMarkersType(strangerClusterMarkers);
},
//添加好友数据
addFriendsMarkersByResult(responseStranger) {
const userPoints = responseStranger.userPoints || [];
const clusters = responseStranger.clusters || [];
// 生成100个经纬度不同的标记
this.clearMarkersByType("friend-single");
this.clearMarkersByType("friend-cluster");
const friendMarkers = userPoints.map((stranger, index) => {
// 为每个标记生成唯一id和随机经纬度偏移
let avatarUrl = '/images/default-stranger.png';
if (stranger.avatar) {
if (stranger.avatar.includes('myqcloud')) {
avatarUrl = stranger.avatar + '?imageMogr2/auto-orient/thumbnail/100x100/quality/85';
} else {
avatarUrl = stranger.avatar
}
}
const marker = {
// id: stranger.customId,
id: MAP_FEED_MARKER_FRIEND_ID + index,
// 基于基础坐标添加随机偏移(确保经纬度不同)
latitude: stranger.latitude,
longitude: stranger.longitude,
iconPath: marker_blank,
type: 'friend-single',
originAvatarUrl:stranger.avatar,
customId: stranger.customId,
clusterColor: '#FF0000',
avatarUrl: avatarUrl,
merchantType: '',
isOnline: stranger.isOnline,
nickname: stranger.nickname, // 昵称加索引区分
battery: 100,
width: 45,
height: 45,
joinCluster: false,
title: stranger.nickname,
radius: 380,
customCallout: {
anchorY: 50,
anchorX: 0,
display: 'ALWAYS'
},
};
return marker;
});
this.updateMarkersByMarkersType(friendMarkers);
const friendClusterMarkers = clusters.map((stranger, index) => {
// 为每个标记生成唯一id和随机经纬度偏移
const marker = {
// id: stranger.customId,
id: MAP_FEED_CLUSTER_FRIEND_ID + index,
latitude: stranger.latitude,
longitude: stranger.longitude,
iconPath: marker_blank,
feedCount: stranger.onlineCount,
customId: stranger.clusterId,
type: 'friend-cluster',
badgeColor: MAP_FEED_MARKER_STYLE.stranger.background,
badgeTextColor: MAP_FEED_MARKER_STYLE.stranger.color,
battery: 100,
customCallout: {
anchorY: 50,
anchorX: 0,
display: 'ALWAYS'
},
radius: 380,
width: 45,
height: 45,
};
return marker;
});
this.updateMarkersByMarkersType(friendClusterMarkers);
},
// 生成0.001到0.01之间的随机数(复用之前的方法)
getRandomNumber() {
const min = 0.001;
const max = 0.01;
return min + Math.random() * (max - min);
},
// 生成随机偏移量(可正负,扩大差异范围)
getRandomOffset() {
const min = -1.0; // 负偏移,扩大范围
const max = 1.0;
return min + Math.random() * (max - min);
},
updateMarkersByMarkersType(toBeUpdateMarkers = []) {
if (toBeUpdateMarkers.length == 0) {
return;
}
// 验证标记点数据
toBeUpdateMarkers.forEach((newMarker, index) => {
// 确保每个标记点都有必要的属性
if (!newMarker.width || !newMarker.height) {
console.warn(`标记点 ${newMarker.id} 缺少尺寸属性,使用默认值`);
newMarker.width = newMarker.width || 45;
newMarker.height = newMarker.height || 45;
}
if (!newMarker.id) {
console.error(`${index} 个标记点缺少 id 属性`);
newMarker.id = Date.now() + index; // 生成临时 ID
}
});
// console.log('进入updateMarkers方法参数', JSON.stringify(toBeUpdateMarkers));
// console.log('allMarkers', JSON.stringify(this.data.allMarkers));
let newMarkers = [];
newMarkers = this.data.allMarkers;
toBeUpdateMarkers.forEach(newMarker => {
// 查找是否已有相同id的marker
const existingIndex = this.data.allMarkers.findIndex(marker => marker.id === newMarker.id);
if (existingIndex > -1) {
// 存在替换该位置的marker更新所有属性
// this.data.allMarkers[existingIndex] = newMarker;
newMarkers[existingIndex] = newMarker
} else {
// 不存在:添加到数组
// this.data.allMarkers.push(newMarker);
newMarkers.push(newMarker);
}
});
console.log('最终显示的markers', JSON.stringify(newMarkers));
this.setData({
allMarkers: newMarkers
});
this.setData({ markers: [] }, () => {
this.setData({ markers: newMarkers });
});
},
// 生成0.001到0.01之间的随机数(复用之前的方法)
getRandomNumber() {
const min = 0.001;
const max = 0.01;
return min + Math.random() * (max - min);
},
// 生成随机偏移量(可正负,扩大差异范围)
getRandomOffset() {
const min = -1.0; // 负偏移,扩大范围
const max = 1.0;
return min + Math.random() * (max - min);
},
// 偶遇模式开关
onDynamicToggle(e) {
if (this.data.mapFeedVisible) {
wx.showToast({
title: '请先关闭动态',
icon: 'none',
duration: 1200
});
return;
}
this.setData({
isOnline: !this.data.isOnline
});
if (this.data.isOnline) {
this.clearMarkersByType("friend-single");
this.clearMarkersByType("friend-cluster");
this.loadNearbyUsers();
this.setData({
markers: this.data.allMarkers
});
} else {
this.clearStranger();
this.loadFriendsLocation()
}
},
//清除陌生人数据
clearStranger() {
//关闭偶遇时 删除陌生人数据
this.data.allMarkers = this.data.allMarkers.filter(item => {
// 返回 true 表示保留该元素false 表示删除
return item.type !== "stranger-single"; // 这里替换为你的判断条件
});
this.data.allMarkers = this.data.allMarkers.filter(item => {
// 返回 true 表示保留该元素false 表示删除
return item.type !== "stranger-cluster"; // 这里替换为你的判断条件
});
this.mapStrangerMarkerLookup.clear();
this.setData({
markers: this.data.allMarkers
});
},
clearMarkersByType(type) {
//关闭偶遇时 删除陌生人数据
this.data.allMarkers = this.data.allMarkers.filter(item => {
// 返回 true 表示保留该元素false 表示删除
return item.type !== type; // 这里替换为你的判断条件
});
// this.setData({
// markers: this.data.allMarkers
// });
},
//清除好友数据
clearFriend() {
//关闭偶遇时 删除陌生人数据
this.data.allMarkers = this.data.allMarkers.filter(item => {
// 返回 true 表示保留该元素false 表示删除
return item.type !== "friend-single"; // 这里替换为你的判断条件
});
this.data.allMarkers = this.data.allMarkers.filter(item => {
// 返回 true 表示保留该元素false 表示删除
return item.type !== "friend-cluster"; // 这里替换为你的判断条件
});
this.mapStrangerMarkerLookup.clear();
this.setData({
markers: this.data.allMarkers
});
},
// 初始化静态数据
initStaticData() {
// 模拟静态数据实际项目中可能从API获取
const staticData = [{
id: 'static1',
title: '热门景点',
description: '游客推荐',
latitude: 44.897383746906186 + 0.005,
longitude: 82.07800276534772 + 0.005,
imageUrl: '/images/map/marker_lan.png'
},
{
id: 'static2',
title: '美食推荐',
description: '当地特色',
latitude: 44.897383746906186 - 0.005,
longitude: 82.07800276534772 + 0.005,
imageUrl: '/images/map/marker_hong.png'
},
{
id: 'static3',
title: '购物中心',
description: '购物天堂',
latitude: 44.897383746906186 + 0.005,
longitude: 82.07800276534772 - 0.005,
imageUrl: '/images/map/marker_yule.png'
}
];
this.setData({
staticDataMarkers: staticData
});
},
// 初始化合作商家标记
initMerchantMarkers() {
try {
// 获取所有商家数据
const merchants = getAllMerchants();
// 将商家数据转换为marker格式
const merchantMarkers = convertMerchantsToMarkers(merchants);
// 保存商家列表到data中用于点击事件查找
this.setData({
merchantList: merchants
});
// 将商家markers添加到地图
if (merchantMarkers && merchantMarkers.length > 0) {
this.updateMarkersByMarkersType(merchantMarkers);
console.log('✅ 已加载', merchantMarkers.length, '个合作商家标记');
}
} catch (error) {
console.error('❌ 初始化商家标记失败:', error);
}
},
scheduleMapFeedRefresh(trigger = 'auto') {
if (!this.mapCtx) {
return;
}
if (!this.data.mapFeedVisible) {
if (this.mapFeedDebounceTimer) {
clearTimeout(this.mapFeedDebounceTimer);
this.mapFeedDebounceTimer = null;
}
return;
}
if (this.mapFeedDebounceTimer) {
clearTimeout(this.mapFeedDebounceTimer);
}
this.mapFeedDebounceTimer = setTimeout(() => {
this.refreshMapFeeds(trigger);
}, MAP_FEED_DEBOUNCE);
},
async refreshMapFeeds(trigger = 'auto') {
if (!this.mapCtx || !this.apiClient) {
return;
}
if (!this.data.mapFeedVisible) {
return;
}
if (!this.mapFeedCache) {
this.mapFeedCache = new Map();
}
try {
const [region, scaleResult] = await Promise.all([
this.getMapRegion(),
this.getMapScale()
]);
const scale = scaleResult?.scale || this.data.scale || 13;
const preset = getFeedScalePreset(scale);
const payload = buildBoundsPayload(region);
if (!payload) {
console.warn('⚠️ 地图区域数据无效,无法请求地图动态');
return;
}
console.log("preset---->" + preset.mode);
console.log("scale---->" + scale);
if (preset.mode === 'nearby') {
payload.maxResults = 50;
} else {
payload.level = preset.level;
payload.maxResults = 80;
}
const cacheKey = buildCacheKey(preset, payload);
const cachedEntry = this.mapFeedCache.get(cacheKey);
this.setData({
mapFeedLoading: true,
mapFeedError: ''
});
let response;
if (preset.mode === 'nearby') {
response = await this.apiClient.getMapFeedsNearby(payload);
} else {
response = await this.apiClient.getMapFeedsAdministrative(payload);
}
if (!response || response.code !== 200 || !response.data) {
throw new Error(response?.message || '地图动态加载失败');
}
const isDataSame = JSON.stringify(this.data.cacheEntryString) === JSON.stringify(response.data);
this.setData({
cacheEntryString: response.data
});
this.mapFeedCache.set(cacheKey, {
data: response.data,
preset,
timestamp: Date.now()
});
if (isDataSame) {
return;
}
if (preset.mode === 'nearby') {
this.addDynamicMarkersByResult(response.data);
} else {
this.addDynamicClusterByResult(response.data);
}
} catch (error) {
console.error('❌ 地图动态刷新失败:', error);
const errMsg = error?.errMsg || error?.message || '';
const isTransient = errMsg.includes('getRegion') || errMsg.includes('getScale');
if (isTransient && this.data.mapFeedVisible) {
setTimeout(() => {
this.scheduleMapFeedRefresh('retry');
}, 600);
}
this.setData({
mapFeedLoading: false,
mapFeedError: isTransient ? '' : (errMsg || '地图动态加载失败')
});
}
},
cropImageToCenter(imagePath) {
return new Promise((resolve, reject) => {
const TARGET_CROP_W = 87;
const TARGET_CROP_H = 77;
const RADIUS = 10;
const SAFE_RADIUS = Math.min(RADIUS, TARGET_CROP_W / 2, TARGET_CROP_H / 2);
if (typeof imagePath !== 'string' || !imagePath.trim()) {
return reject(new Error('图片路径不能为空'));
}
wx.getImageInfo({
src: imagePath,
success: (imgInfo) => {
const { width: ORI_W, height: ORI_H, path: ORI_LOCAL_PATH } = imgInfo;
// 计算等比缩放比例
const targetRatio = TARGET_CROP_W / TARGET_CROP_H;
const imageRatio = ORI_W / ORI_H;
let scaledW, scaledH;
if (imageRatio > targetRatio) {
scaledH = TARGET_CROP_H;
scaledW = (ORI_W * TARGET_CROP_H) / ORI_H;
} else {
scaledW = TARGET_CROP_W;
scaledH = (ORI_H * TARGET_CROP_W) / ORI_W;
}
// 计算裁剪中心点
const centerX = (scaledW - TARGET_CROP_W) / 2;
const centerY = (scaledH - TARGET_CROP_H) / 2;
const cropX = Math.max(0, centerX);
const cropY = Math.max(0, centerY);
const query = wx.createSelectorQuery();
query.select('#cropCanvas')
.fields({ node: true, size: true })
.exec((res) => {
if (!res[0] || !res[0].node) {
return reject(new Error('未找到Canvas画布'));
}
const canvas = res[0].node;
const ctx = canvas.getContext('2d');
const dpr = wx.getSystemInfoSync().pixelRatio;
// 正确设置Canvas尺寸
canvas.width = TARGET_CROP_W * dpr;
canvas.height = TARGET_CROP_H * dpr;
ctx.scale(dpr, dpr);
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
const image = canvas.createImage();
image.src = ORI_LOCAL_PATH;
image.onload = () => {
try {
ctx.clearRect(0, 0, TARGET_CROP_W, TARGET_CROP_H);
// 创建圆角裁剪路径
ctx.beginPath();
this.createRoundedPath(ctx, 0, 0, TARGET_CROP_W, TARGET_CROP_H, SAFE_RADIUS);
ctx.clip();
// 绘制图片
ctx.drawImage(image, -cropX, -cropY, scaledW, scaledH);
// 导出图片
wx.canvasToTempFilePath({
canvas: canvas,
destWidth: TARGET_CROP_W * dpr,
destHeight: TARGET_CROP_H * dpr,
fileType: 'png',
quality: 1,
success: (res) => resolve(res.tempFilePath),
fail: (err) => reject(new Error(`导出失败:${err.errMsg}`))
});
} catch (e) {
reject(new Error(`绘制失败:${e.message}`));
}
};
image.onerror = () => reject(new Error('图片加载失败'));
});
},
fail: (err) => reject(new Error(`获取图片信息失败:${err.errMsg}`))
});
});
},
// 圆角路径创建函数
createRoundedPath(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.arcTo(x + width, y, x + width, y + height, radius);
ctx.arcTo(x + width, y + height, x, y + height, radius);
ctx.arcTo(x, y + height, x, y, radius);
ctx.arcTo(x, y, x + width, y, radius);
ctx.closePath();
},
/**
* 小程序版 - 动态添加Marker保留你的原始逻辑仅适配裁剪方法
*/
async addDynamicMarkersByResult(responseStranger) {
console.log("responseStranger----->" + JSON.stringify(responseStranger));
const userPoints = responseStranger.points || [];
const friendMarkers = userPoints.map(async (stranger, index) => { // 注意async
let thumbnail = "/images/findme-logo.png";
let avatarUrl = '';
try {
if (stranger.thumbnail && stranger.thumbnail.includes('myqcloud')) {
// 清理腾讯云原有缩放参数(保留你的原始逻辑)
const cleanImageUrl = stranger.thumbnail.replace("thumbnail=300x300", "");
// 调用小程序版裁剪方法
thumbnail = await this.cropImageToCenter(stranger.thumbnail);
} else {
avatarUrl = stranger.thumbnail; // 保留你的原始逻辑
}
if (avatarUrl) {
thumbnail = marker_blank; // 保留你的原始逻辑需确保marker_blank已定义
}
} catch (error) {
// 裁剪失败兜底(保留你的原始逻辑)
console.error(`${index}个marker裁剪失败`, error);
thumbnail = "/images/findme-logo.png";
}
console.log("thumbnail-->" + thumbnail);
// 保留你原始的marker结构仅调整宽高为86/77
const marker = {
id: Number(MAP_FEED_SINGLE_BASE_ID + index), // 需确保MAP_FEED_SINGLE_BASE_ID已定义
latitude: stranger.location.latitude,
longitude: stranger.location.longitude,
iconPath: thumbnail ? thumbnail : "/images/findme-logo.png",
type: 'map-feed-single',
feedUuid: stranger.feedUuid,
likeCount: stranger.likeCount,
commentCount: stranger.commentCount,
clusterColor: '#FF0000',
avatarUrl: avatarUrl,
originalUrl: stranger.thumbnail ? stranger.thumbnail : "/images/findme-logo.png",
merchantType: '',
zIndex: 10,
battery: 100,
width: 87, // 裁剪宽度
height: 77, // 裁剪高度
imageLoaded: false,
radius: 380,
joinCluster: false,
customCallout: {
anchorY: 86,
anchorX: 0,
display: 'ALWAYS'
},
};
return marker;
});
// 等待所有marker异步处理完成
const resolvedMarkers = await Promise.all(friendMarkers);
// 保留你原始的清空/更新逻辑
this.clearMarkersByType("map-feed-single");
this.clearMarkersByType("map-feed-cluster");
this.updateMarkersByMarkersType(resolvedMarkers);
},
//添加区城市省级国家级动态数据
addDynamicClusterByResult(responseStranger) {
const userPoints = responseStranger.userPoints || [];
const clusters = responseStranger.clusters || [];
const friendMarkers = userPoints.map((stranger, index) => {
// 为每个标记生成唯一id和随机经纬度偏移
const marker = {
id: Number(MAP_FEED_SINGLE_BASE_ID + index),
// 基于基础坐标添加随机偏移(确保经纬度不同)
latitude: stranger.latitude,
longitude: stranger.longitude,
iconPath: marker_blank,
type: 'map-feed-single',
customId: stranger.customId,
clusterColor: '#FF0000',
avatarUrl: stranger.thumbnail ? stranger.thumbnail : '/images/findme-logo.png',
merchantType: '',
isOnline: stranger.isOnline,
nickname: stranger.nickname, // 昵称加索引区分
battery: 100,
width: 45,
height: 45,
radius: 380,
joinCluster: false,
title: stranger.nickname,
customCallout: {
anchorY: 50,
anchorX: 0,
display: 'ALWAYS'
},
};
return marker;
});
this.updateMarkersByMarkersType(friendMarkers);
const friendClusterMarkers = clusters.filter(stranger => stranger.count !== 1) // 过滤掉 count 为 1 的数据
// const friendClusterMarkers = clusters // 过滤掉 count 为 1 的数据
.map((stranger, index) => {
const marker = {
// id: stranger.customId,
id: Number(MAP_FEED_CLUSTER_BASE_ID + index),
latitude: stranger.location.latitude,
longitude: stranger.location.longitude,
iconPath: marker_blank,
feedCount: stranger.count,
customId: stranger.id,
type: 'map-feed-cluster',
badgeColor: MAP_FEED_MARKER_STYLE.cluster.background,
badgeTextColor: MAP_FEED_MARKER_STYLE.cluster.color,
battery: 100,
customCallout: {
anchorY: 50,
anchorX: 0,
display: 'ALWAYS'
},
radius: 380,
width: 45,
height: 45,
};
return marker;
});
// if (friendClusterMarkers.length > 0) {
this.clearMarkersByType("map-feed-single");
this.clearMarkersByType("map-feed-cluster");
// }
this.updateMarkersByMarkersType(friendClusterMarkers);
},
// 图片预览
previewImage(e) {
try {
// 获取当前点击的图片索引和动态索引
const originalurl = e.currentTarget.dataset.originalurl;
// 优先使用原始图片URL或高质量图片确保预览完整清晰的图片
const imageUrls = [originalurl];
// 🔥 设置标志,防止预览关闭后触发页面刷新
this._skipNextOnShowReload = true;
console.log("originalurl--->"+imageUrls);
// 调用微信小程序的图片预览API
wx.previewImage({
current: imageUrls[0], // 当前显示图片的URL
urls: imageUrls, // 需要预览的图片URL列表
success: () => {
// 预览打开成功,标志已设置,关闭时会触发 onShow
},
fail: (err) => {
console.error('图片预览失败:', err);
// 预览失败,清除标志
this._skipNextOnShowReload = false;
wx.showToast({
title: '预览图片失败',
icon: 'none'
});
}
});
} catch (error) {
console.error('图片预览过程中出错:', error);
// 出错时清除标志
this._skipNextOnShowReload = false;
wx.showToast({
title: '预览图片失败',
icon: 'none'
});
}
},
// 触摸开始
onTouchStart(e) {
this.setData({
startY: e.touches[0].clientY,
isMoving: true
});
},
// 触摸移动
onTouchMove(e) {
if (!this.data.isMoving) return;
const moveY = e.touches[0].clientY;
const diff = moveY - this.data.startY;
// 只允许向下滑动
if (diff > 0) {
this.setData({
modalTranslateY: diff
});
}
},
// 触摸结束
onTouchEnd() {
// 滑动距离超过50px则关闭弹窗
if (this.data.modalTranslateY > 50) {
if(this.data.searchResultNavigationVisible==true){
this.handleHideBottmNavigation();
this.setData({
modalTranslateY: 0,
isMoving: false
});
return;
}
if(this.data.shareShareVisible==true){
this.handleHideShareBottm();
this.setData({
modalTranslateY: 0,
isMoving: false
});
return;
}
if(this.data.searchResultInfoModalVisible==true){
this.handleHideBottm();
}
} else {
// 否则复位
this.setData({
modalTranslateY: 0,
isMoving: false
});
}
},
//开启动态
enableMapFeedView() {
this.closeUserCard();
this.hideFeedBubble();
this.setData({
mapFeedVisible: true,
mapFeedError: ''
}, () => {
// 更新地图动态数据标记
this.scheduleMapFeedRefresh('manual');
});
wx.showToast({
title: '已开启附近动态',
icon: 'none',
duration: 1200
});
},
disableMapFeedView(showToast = true) {
if (this.mapFeedDebounceTimer) {
clearTimeout(this.mapFeedDebounceTimer);
this.mapFeedDebounceTimer = null;
}
this.hideFeedBubble();
if (this.mapFeedMarkerLookup) {
this.mapFeedMarkerLookup.clear();
}
this.setData({
mapFeedVisible: false,
mapFeedMarkers: [],
mapFeedLoading: false,
mapFeedError: ''
}, () => {
this.data.allMarkers = this.data.allMarkers.filter(item => {
// 返回 true 表示保留该元素false 表示删除
return item.type !== "map-feed-single"; // 这里替换为你的判断条件
});
this.data.allMarkers = this.data.allMarkers.filter(item => {
// 返回 true 表示保留该元素false 表示删除
return item.type !== "map-feed-cluster"; // 这里替换为你的判断条件
});
this.setData({
markers: this.data.allMarkers
});
});
if (showToast) {
wx.showToast({
title: '已关闭附近动态',
icon: 'none',
duration: 1200
});
}
},
//关闭或开启动态
toggleMapFeedView() {
if (this.data.mapFeedVisible) {
this.disableMapFeedView(true);
if (this.data.isOnline) {
this.loadNearbyUsers();
}
if (!this.data.isOnline) {
this.loadFriendsLocation();
}
return;
}
if (!this.ensureLoggedInForAction()) {
return;
}
this.clearStranger();
this.clearFriend();
this.enableMapFeedView();
},
showFeedBubble(bubble) {
this.setData({
activeFeedBubble: bubble,
activeFeedBubbleLoading: false
});
},
hideFeedBubble() {
this.setData({
activeFeedBubble: null,
activeFeedBubbleSingle: null,
activeFeedBubbleLoading: false,
activeFeedSingleVisible: false
});
},
async handleMapFeedMarkerTap(markerMeta) {
if (!markerMeta) {
return;
}
// const markerMeta = this.mapFeedMarkerLookup?.get(marker.id);
// if (!markerMeta) {
// wx.showToast({
// title: '内容已更新,请重试',
// icon: 'none'
// });
// return;
// }
if (markerMeta.type === 'map-feed-single') {
let response = await this.apiClient.getFeedsDetail(markerMeta.feedUuid);
let nickName = '';
let content = '';
let avatar = '';
if (response.data) {
nickName = response.data.user.nickname;
content = response.data.content;
avatar = response.data.user.avatar;
let formatted_time = this.formatCommentTime(response.data.createdAt);
const baseBubble = buildBubbleData({
type: markerMeta.type,
title: markerMeta.payload?.name || '附近热力区',
nickname: nickName,
avatar: avatar,
content: content,
createdAt: formatted_time,
thumbnail: markerMeta.originalUrl,
location: markerMeta.location,
tone: 'sunset'
});
this.setData({
activeFeedBubbleSingle: baseBubble,
activeFeedSingleVisible: true
});
}
return;
}
const radius = markerMeta.location?.radius || 320;
const countLabel = formatFeedCountLabel(markerMeta.payload?.count || 0);
const baseBubble = buildBubbleData({
type: markerMeta.type,
title: markerMeta.payload?.name || '附近热力区',
// subtitle: markerMeta.payload?.count ? `含 ${countLabel}` : formatRadiusLabel(radius),
chip: countLabel,
// heat: formatHeatLabel(markerMeta.payload?.hotScore),
// thumbnail: resolveFeedThumbnail(markerMeta.payload),
feeds: markerMeta.feedCount,
location: markerMeta.location,
thumbnail: markerMeta.avatarUrl,
// radiusLabel: formatRadiusLabel(radius),
tone: 'sunset'
});
this.setData({
activeFeedBubble: baseBubble,
activeFeedBubbleLoading: false
});
// this.loadClusterPreview(markerMeta);
},
// 格式化评论时间
formatCommentTime(timeStr) {
if (!timeStr) return '';
const commentTime = new Date(timeStr);
if (isNaN(commentTime.getTime())) return '';
const now = new Date();
const diffMinutes = Math.floor((now - commentTime) / (1000 * 60));
// 5分钟内显示"刚刚"
if (diffMinutes < 5) return '刚刚';
// 格式化日期时间
const year = commentTime.getFullYear();
const month = commentTime.getMonth() + 1; // 不加前导0直接显示月份
const day = commentTime.getDate();
const hour = String(commentTime.getHours()).padStart(2, '0');
const minute = String(commentTime.getMinutes()).padStart(2, '0');
// 当前年份显示不带年份的日期和时间例如8月24日 17:11
// 非当前年份显示带年份的日期和时间例如2024年 8月24日 17:11
const currentYear = now.getFullYear();
return year === currentYear
? `${month}${day}${hour}:${minute}`
: `${year}${month}${day}${hour}:${minute}`;
},
async loadClusterPreview(markerMeta) {
if (!markerMeta || !markerMeta.payload) {
return;
}
try {
this.setData({
activeFeedBubbleLoading: true
});
const response = await this.apiClient.getMapClusterFeeds({
location: {
latitude: Number(markerMeta.payload?.location?.latitude),
longitude: Number(markerMeta.payload?.location?.longitude)
},
radius: 380,
limit: MAP_FEED_BUBBLE_LIMIT
});
if (!response || response.code !== 200) {
throw new Error(response?.message || '加载聚合动态失败');
}
const feeds = (response.data?.feeds || []).map((feed) => {
const likeCount = feed.interactions?.likeCount || 0;
const commentCount = feed.interactions?.commentCount || 0;
let description = '刚刚更新';
if (likeCount > 0 || commentCount > 0) {
description = `👍 ${likeCount} · 💬 ${commentCount}`;
}
return {
uuid: feed.uuid,
title: feed.location?.name || feed.user?.nickname || '附近动态',
description,
thumbnail: resolveFeedThumbnail({
thumbnail: feed.media?.[0]?.thumbnailUrl || feed.media?.[0]?.url,
contentType: feed.type
}),
hotScore: feed.interactions?.likeCount || 0
};
});
const existingBubble = this.data.activeFeedBubble || {};
const radius = existingBubble.radius || 320;
const clusterCount = markerMeta.payload?.count || feeds.length;
const countLabel = formatFeedCountLabel(clusterCount);
const bubble = buildBubbleData({
type: markerMeta.type,
title: markerMeta.payload?.name || existingBubble.title || '附近热力区',
subtitle: markerMeta.payload?.count ? `${countLabel}` : (existingBubble.subtitle || formatRadiusLabel(radius)),
chip: countLabel,
heat: formatHeatLabel(markerMeta.payload?.hotScore),
thumbnail: markerMeta.payload?.thumbnail || feeds[0]?.thumbnail || existingBubble.thumbnail,
feeds,
location: markerMeta.location,
radius,
radiusLabel: existingBubble.radiusLabel || formatRadiusLabel(radius),
tone: existingBubble.tone || 'sunset'
});
this.showFeedBubble(bubble);
} catch (error) {
console.error('加载聚合预览失败:', error);
this.setData({
activeFeedBubbleLoading: false
});
wx.showToast({
title: error.message || '加载失败',
icon: 'none'
});
}
},
onFeedBubbleMoreTap(e) {
if (!this.ensureLoggedInForAction()) {
return;
}
const {
lat,
lng,
radius
} = e.currentTarget.dataset || {};
const bubble = this.data.activeFeedBubble || {};
const latitude = Number(lat || bubble.location?.latitude || this.data.latitude);
const longitude = Number(lng || bubble.location?.longitude || this.data.longitude);
const radiusValue = Number(radius || bubble.radius || 200);
if (Number.isNaN(latitude) || Number.isNaN(longitude)) {
wx.showToast({
title: '位置信息不可用',
icon: 'none'
});
return;
}
this.hideFeedBubble();
const redirectToken = Date.now();
const appInstance = getApp();
if (appInstance && appInstance.globalData) {
appInstance.globalData.mapFeedRedirect = {
latitude,
longitude,
radius: Math.max(50, Math.round(radiusValue)),
feedUuid: bubble?.feeds?.[0]?.uuid || '',
mode: 'map',
token: redirectToken
};
}
wx.switchTab({
url: '/pages/circle/circle'
});
},
onFeedBubbleItemTap(e) {
if (!this.ensureLoggedInForAction()) {
return;
}
const {
uuid,
lat,
lng,
radius
} = e.currentTarget.dataset || {};
const bubble = this.data.activeFeedBubble || {};
const latitude = Number(lat || bubble.location?.latitude || this.data.latitude);
const longitude = Number(lng || bubble.location?.longitude || this.data.longitude);
const radiusValue = Number(radius || bubble.radius || 200);
if (Number.isNaN(latitude) || Number.isNaN(longitude)) {
wx.showToast({
title: '位置信息不可用',
icon: 'none'
});
return;
}
this.hideFeedBubble();
const redirectToken = Date.now();
const appInstance = getApp();
if (appInstance && appInstance.globalData) {
appInstance.globalData.mapFeedRedirect = {
latitude,
longitude,
radius: Math.max(50, Math.round(radiusValue)),
feedUuid: uuid || '',
mode: 'map',
token: redirectToken
};
}
wx.switchTab({
url: '/pages/circle/circle'
});
},
getMapRegion() {
return new Promise((resolve, reject) => {
if (!this.mapCtx) {
reject(new Error('地图上下文未初始化'));
return;
}
this.mapCtx.getRegion({
success: resolve,
fail: reject
});
});
},
getMapScale() {
return new Promise((resolve, reject) => {
if (!this.mapCtx) {
reject(new Error('地图上下文未初始化'));
return;
}
this.mapCtx.getScale({
success: resolve,
fail: reject
});
});
},
// 加载浮动UI相关数据
async loadFloatingUIData() {
try {
// 并行加载各种统计数据
await Promise.all([
this.loadUnreadMessageCount(),
this.loadFriendRequestCount(),
this.loadNearbyCount()
]);
} catch (error) {
console.error('加载浮动UI数据失败:', error);
}
},
// 加载未读消息数
async loadUnreadMessageCount() {
try {
// 这里应该调用消息API获取未读数
// const response = await chatAPI.getTotalUnreadCount();
// this.updateUnreadMessageCount(response.data?.count || 0);
// 临时模拟数据
this.updateUnreadMessageCount(0);
} catch (error) {
console.error('加载未读消息数失败:', error);
this.updateUnreadMessageCount(0);
}
},
// 加载好友请求数
async loadFriendRequestCount() {
try {
// 这里应该调用好友API获取请求数
// const response = await friendAPI.getFriendRequestCount();
// this.updateFriendRequestCount(response.data?.count || 0);
// 临时模拟数据
this.updateFriendRequestCount(0);
} catch (error) {
console.error('加载好友请求数失败:', error);
this.updateFriendRequestCount(0);
}
},
// 加载附近的人数量
async loadNearbyCount() {
try {
this.updateNearbyCount(this.data.strangersCount);
} catch (error) {
console.error('加载附近的人数量失败:', error);
this.updateNearbyCount(0);
}
},
// 🔥 ===== 浮动UI事件处理 =====
// 跳转到个人主页
openProfile() {
wx.navigateTo({
url: '/subpackages/profile/profile/profile'
});
},
// 打开好友页面
openFriends() {
wx.navigateTo({
url: '/pages/social/friends/friends'
});
},
// 打开消息页面
openMessages() {
wx.navigateTo({
url: '/pages/message/message'
});
},
// 打开WebSocket测试页面开发调试用
openWebSocketTest() {
wx.navigateTo({
url: '/subpackages/dev-tools/websocket-test/websocket-test'
});
},
// ===== 搜索功能相关方法 =====
// 显示搜索框
showSearchBox() {
this.setData({
showSearchBox: true,
searchKeyword: ''
});
},
// 隐藏搜索框
hideSearchBox() {
this.setData({
showSearchBox: false,
searchKeyword: ''
});
},
// 搜索输入处理
onSearchInput(e) {
const keyword = e.detail.value;
this.setData({
searchKeyword: keyword
});
// 如果输入内容不为空,开始搜索
if (keyword.trim()) {
// 模拟搜索延迟
setTimeout(() => {
this.searchPlaces(keyword);
}, 300);
} else {
// 清空搜索结果
this.setData({
searchResults: []
});
}
},
// 搜索确认处理
onSearchConfirm() {
const keyword = this.data.searchKeyword.trim();
if (keyword) {
// 如果已有搜索结果,直接定位第一个结果
if (this.data.searchResults && this.data.searchResults.length > 0) {
this.onSearchResultTap({
currentTarget: {
dataset: {
item: this.data.searchResults[0]
}
}
});
} else {
// 否则执行搜索
this.searchPlaces(keyword);
wx.showToast({
title: `搜索: ${keyword}`,
icon: 'none'
});
}
}
},
// 搜索地点
searchPlaces(keyword) {
// 显示加载提示
wx.showLoading({
title: '搜索中...',
mask: true
});
try {
// 高德地图
const params = {
key: config.amapKey,
keywords: keyword,
city: this.data.currentCity || '全国',
citylimit: false,
location: this.data.myLocation ? `${this.data.myLocation.longitude},${this.data.myLocation.latitude}` : ''
};
// 调用高德地图API
wx.request({
url: baseAmapUrl + '/assistant/inputtips',
data: params,
method: 'GET',
header: {
'content-type': 'application/json'
},
success: (res) => {
wx.hideLoading();
if (res.statusCode === 200 && res.data && res.data.status === '1' && res.data.tips) {
// 转换格式
const searchResults = res.data.tips.map((tip, index) => {
// 从location中提取经纬度
let latitude = 0;
let longitude = 0;
if (tip.location && typeof tip.location === 'string' && tip.location.split(',').length === 2) {
const [lng, lat] = tip.location.split(',');
longitude = parseFloat(lng);
latitude = parseFloat(lat);
}
// 根据类型设置不同的图标
let icon = '📍';
if (tip.name.includes('酒店')) icon = '🏨';
else if (tip.name.includes('餐厅')) icon = '🍽️';
else if (tip.name.includes('公园')) icon = '🌳';
else if (tip.name.includes('地铁')) icon = '🚇';
else if (tip.name.includes('购物中心') || tip.name.includes('广场')) icon = '🏬';
return {
id: `search_${index}`,
name: tip.name,
address: tip.address || tip.district || '地址不详',
latitude: latitude,
longitude: longitude,
district: tip.district,
icon: icon
};
});
this.setData({
searchResults: searchResults
});
} else {
console.error('❌ 搜索失败,返回数据异常:', res.data);
wx.showToast({
title: '未找到相关地点',
icon: 'none'
});
this.setData({
searchResults: []
});
}
},
fail: (error) => {
wx.hideLoading();
console.error('❌ 搜索请求失败:', error);
wx.showToast({
title: '搜索失败,请检查网络',
icon: 'none'
});
this.setData({
searchResults: []
});
}
});
} catch (error) {
wx.hideLoading();
console.error('❌ 搜索过程发生异常:', error);
wx.showToast({
title: '搜索过程发生异常',
icon: 'none'
});
}
},
// 点击搜索结果
onSearchResultTap(e) {
const item = e.currentTarget.dataset.item;
this.setData({
selectResult: item,
selectedMerchant: item
});
// 隐藏搜索框和搜索结果
this.setData({
showSearchBox: false,
searchResults: []
});
// 在地图上添加标记
const marker = {
id: new Date().getTime(),
latitude: item.latitude,
longitude: item.longitude,
width: 40,
height: 40,
type: 'search', // 标记类型:搜索结果
iconPath: '/images/map/marker-select-position.png',
callout: {
content: item.name,
display: 'BYCLICK'
}
};
this.mapCtx.moveToLocation({
latitude: item.latitude,
longitude: item.longitude
});
this.setData({
latitude: item.latitude,
longitude: item.longitude,
currentMapScale: 17
});
let that = this;
setTimeout(() => {
that.updateScale()
}, 1000)
// 更新标记数组
console.log("markers--->1-->" + this.data.markers.length)
const filteredMarkers = this.data.allMarkers.filter(marker => marker.type !== 'search');
this.setData({
markers: filteredMarkers,
allMarkers: filteredMarkers
});
this.data.allMarkers.push(marker);
this.setData({
markers: this.data.allMarkers,
merchantName: item.name,
merchant: item.district + item.address,
});
console.log("markers--->2-->" + this.data.markers.length)
this.setData({
searchResultInfoModalVisible: true,
modalTranslateY:0,
shouldFollowLocation: false
})
// 显示提示信息
wx.showToast({
title: "定位成功",
icon: 'success'
});
},
handleHideBottm() {
const filteredMarkers = this.data.allMarkers.filter(marker => marker.type !== 'search');
this.setData({
markers: filteredMarkers,
allMarkers: filteredMarkers
});
this.setData({
placeMarkId: '',
mapClickCollect: '收藏',
searchResultInfoModalVisible: false,
shouldFollowLocation: false
})
},
handleHideBottmNavigation() {
this.setData({
searchResultNavigationVisible: false
})
},
onSharechant() {
this.setData({
shareShareVisible: true,
})
},
onNavigation() {
let distance = this.data.myLocation ? this.calculateDistance(
this.data.myLocation.latitude, this.data.myLocation.longitude,
this.data.selectResult.latitude, this.data.selectResult.longitude
) : 0;
distance = this.formatDistance(distance);
this.setData({
searchResultNavigationVisible: true,
distance: distance
})
},
onNavigationTap(e) {
const type = e.currentTarget.dataset.type;
if (type == "gaode") {
this.guideToDouyin("请手动打开高德地图粘贴");
} else if (type == "baidu") {
this.guideToDouyin("请手动打开百度地图粘贴");
} else if (type == "tengxun") {
this.guideToDouyin("请手动打开腾讯地图粘贴");
} else {
this.guideToDouyin("地址已复制");
}
},
handleShare(e) {
const type = e.currentTarget.dataset.type;
console.log("share--->" + type);
if (type == "douyin") {
this.guideToDouyin("请手动打开抖音粘贴");
} else if (type == "weibo") {
this.guideToDouyin("请手动打开微博粘贴");
} else if (type == "email") {
this.guideToDouyin("请手动打开邮箱粘贴");
} else if (type == "qq") {
this.guideToDouyin("请手动打开QQ粘贴");
} else if (type == "copy") {
this.guideToDouyin("地址已复制");
}
},
// 引导用户手动打开抖音
guideToDouyin(title) {
// 先复制文字或保存图片(参考之前的代码)
this.copyShareText(); // 假设已实现复制文字的方法
// 提示用户手动打开抖音
wx.showModal({
title: title,
content: this.data.merchant,
showCancel: false,
confirmText: '确定'
});
},
// 复制要分享的文字
copyShareText() {
const text = this.data.merchant;
wx.setClipboardData({
data: text,
success: () => {}
});
},
// 配置分享到聊天的内容(必填)
onShareAppMessage() {
return {
title: "Find Me", // 分享的文字内容
path: '/custom-tab-bar/index/index', // 点击分享卡片跳转的页面
imageUrl: "/images/findme-logo.png" // 分享时的图片(可选,增强展示效果)
};
},
// 在线图加载成功:标记为已加载
handleAvatarLoaded(e) {
const {
index
} = e.currentTarget.dataset; // 获取当前 Marker 索引
this.setData({
[`markers[${index}].imageLoaded`]: true // 关键:给对应 Marker 添加加载完成状态
});
},
// 在线图加载失败404/网络错误):保持默认图显示(避免在线图一直透明)
handleAvatarError(e) {
const {
index
} = e.currentTarget.dataset;
// 可选:如果想加载失败也显示默认图,这里不用改(在线图保持 opacity:0
// 若想重试,可添加重试逻辑:
// const markers = this.data.markers;
// markers[index].avatarUrl = `${markers[index].avatarUrl}?t=${Date.now()}`; // 加时间戳避免缓存
// this.setData({ markers });
},
// 检查好友关系
async checkFriendRelation(e) {
let customId = e.currentTarget.dataset.userid;
try {
const friendAPI = require('../../utils/friend-api.js');
// 显示加载提示
wx.showLoading({
title: '加载中...',
mask: true
});
// 获取好友详情
const friendDetailResponse = await friendAPI.getFriendDetail(customId);
wx.hideLoading();
if (friendDetailResponse && friendDetailResponse.code === 0 && friendDetailResponse.data) {
// 成功获取好友详情,说明是好友关系
this.navigateToFriendProfile(customId);
return;
}
// 跳转到陌生人主页
this.navigateToStrangerProfile(customId);
} catch (error) {
wx.hideLoading();
console.error('检查好友关系失败:', error);
// 跳转到陌生人主页
this.navigateToStrangerProfile(customId);
}
},
// 跳转到好友主页
navigateToFriendProfile(customId) {
if (!customId) {
console.error('customId 为空,无法跳转');
wx.showToast({ title: '用户ID无效', icon: 'none' });
return;
}
const targetUrl = `/subpackages/social/friend-detail/friend-detail?customId=${customId}`;
console.log('准备跳转到好友页面:', targetUrl);
wx.navigateTo({
url: targetUrl,
success: () => {
console.log('✅ 成功跳转到好友页面');
},
fail: (err) => {
console.error('❌ navigateTo 跳转好友页面失败:', err);
// 如果 navigateTo 失败(可能是页面栈已满),尝试使用 redirectTo
wx.redirectTo({
url: targetUrl,
success: () => {
console.log('✅ redirectTo 成功跳转到好友页面');
},
fail: (err2) => {
console.error('❌ redirectTo 也失败:', err2);
wx.showToast({
title: '跳转失败,请重试',
icon: 'none',
duration: 2000
});
}
});
}
});
},
// 跳转到陌生人主页
navigateToStrangerProfile(customId) {
if (!customId) {
console.error('customId 为空,无法跳转');
wx.showToast({ title: '用户ID无效', icon: 'none' });
return;
}
const targetUrl = `/subpackages/social/user-preview/user-preview?customId=${customId}`;
console.log('准备跳转到陌生人页面:', targetUrl);
wx.navigateTo({
url: targetUrl,
success: () => {
console.log('✅ 成功跳转到陌生人页面');
},
fail: (err) => {
console.error('❌ navigateTo 跳转陌生人页面失败:', err);
// 如果 navigateTo 失败(可能是页面栈已满),尝试使用 redirectTo
wx.redirectTo({
url: targetUrl,
success: () => {
console.log('✅ redirectTo 成功跳转到陌生人页面');
},
fail: (err2) => {
console.error('❌ redirectTo 也失败:', err2);
wx.showToast({
title: '跳转失败,请重试',
icon: 'none',
duration: 2000
});
}
});
}
});
},
handleHideShareBottm() {
this.setData({
shareShareVisible: false
})
},
// ===== 更多菜单相关方法 =====
// 切换更多菜单显示状态
toggleMoreMenu() {
this.setData({
showMoreMenu: !this.data.showMoreMenu,
showMapSettings: false // 确保地图设置不显示
});
},
// 隐藏更多菜单
hideMoreMenu() {
this.setData({
showMoreMenu: false
});
},
// 处理添加好友
handleAddFriend() {
this.hideMoreMenu();
wx.navigateTo({
url: '/subpackages/social/search/search'
});
},
// 处理发起群聊
handleStartGroupChat() {
this.hideMoreMenu();
wx.navigateTo({
url: '/subpackages/group/create-group/create-group'
});
},
// 处理显示二维码
handleShowQRCode() {
this.hideMoreMenu();
wx.navigateTo({
url: '/subpackages/qr/qr-code/qr-code'
});
},
// 处理扫一扫
handleScanQRCode() {
this.hideMoreMenu();
wx.scanCode({
onlyFromCamera: false,
success: (res) => {
const scanResult = res.result || '';
console.log('扫码结果:', scanResult);
// 处理 FindMe 用户二维码格式: FINDME:{customId}
if (scanResult && scanResult.startsWith('FINDME:')) {
const customId = (scanResult.split(':')[1] || '').trim();
if (!customId) {
wx.showToast({
title: '无效的用户二维码',
icon: 'none'
});
return;
}
// 检查是否是自己
const currentUser = app.globalData.userInfo?.user;
if (currentUser && currentUser.customId === customId) {
wx.showToast({
title: '这是你自己的二维码',
icon: 'none'
});
return;
}
// 检查好友关系并跳转
this.handleScanResult(customId);
} else {
wx.showToast({
title: '无效的二维码这不是FindMe的用户二维码',
icon: 'none'
});
}
},
fail: (err) => {
// 用户取消不提示错误
if (err.errMsg && !err.errMsg.includes('cancel')) {
console.error('扫一扫失败:', err);
wx.showToast({
title: '扫码失败,请重试',
icon: 'none'
});
}
}
});
},
// 处理扫码结果(检查好友关系并跳转)
async handleScanResult(customId) {
if (!customId) {
wx.showToast({
title: '用户ID无效',
icon: 'none'
});
return;
}
try {
const friendAPI = require('../../utils/friend-api.js');
// 显示加载提示
wx.showLoading({
title: '加载中...',
mask: true
});
// 获取好友详情
const friendDetailResponse = await friendAPI.getFriendDetail(customId);
wx.hideLoading();
// 判断是否是好友code === 0 且有 data 数据
const isFriend = friendDetailResponse?.code === 0 && friendDetailResponse?.data;
console.log('扫码好友关系判断结果:', {
customId,
isFriend,
responseCode: friendDetailResponse?.code,
hasData: !!friendDetailResponse?.data
});
// 根据好友关系跳转到对应页面
if (isFriend) {
this.navigateToFriendProfile(customId);
} else {
this.navigateToStrangerProfile(customId);
}
} catch (error) {
wx.hideLoading();
console.error('检查好友关系失败:', error);
// 如果接口调用失败,默认当作陌生人处理
console.log('接口调用失败,当作陌生人处理');
this.navigateToStrangerProfile(customId);
}
},
// ===== 地图设置相关方法 =====
// 打开地图设置
openMapSettings() {
this.setData({
showMapSettings: true,
showMoreMenu: false // 确保更多菜单不显示
});
},
// 关闭地图设置
closeMapSettings() {
// 先添加滑出动画类
this.setData({
isClosingMapSettings: true
});
// 等待动画完成后再隐藏弹窗
setTimeout(() => {
this.setData({
showMapSettings: false,
isClosingMapSettings: false
});
}, 300); // 与CSS动画时间一致
},
// 设置地图图层
setMapLayer(e) {
const layer = e.currentTarget.dataset.layer;
this.setData({
showTraffic: false,
currentMapType: layer,
enableSatellite: layer === 'satellite'
});
wx.showToast({
title: this.getLayerTitle(layer),
icon: 'none'
});
},
// 获取图层标题
getLayerTitle(layer) {
const titles = {
'standard': '标准地图',
'satellite': '卫星地图',
'jiache': '驾车模式',
'gonggong': '公共交通模式'
};
return titles[layer] || '地图模式';
},
// 打开好友选择弹窗
onOpenFriendSelectModal() {
// 同步selected字段
const selectedIds = this.data.poiRemindSelectedFriends.map(f => f.userId);
const filteredFriendsList = this.data.filteredFriendsList.map(f => ({
...f,
selected: selectedIds.includes(f.userId)
}));
this.setData({
showFriendSelectModal: true,
filteredFriendsList
});
},
// 搜索输入
onFriendSearchInput(e) {
const text = e.detail.value.trim();
const list = this.data.allFriendsList.filter(f => !text || (f.nickname && f.nickname.indexOf(text) !== -1));
// 同步selected字段
const selectedIds = this.data.poiRemindSelectedFriends.map(f => f.userId);
const filteredFriendsList = list.map(f => ({
...f,
selected: selectedIds.includes(f.userId)
}));
this.setData({
friendSearchText: text,
filteredFriendsList
});
},
// 显示附近的人
showNearbyPeople() {
// 切换到显示附近的人
this.setData({
currentFilter: 'strangers'
});
// 刷新附近用户数据
this.loadNearbyUsers();
// 延迟显示toast等待数据加载完成
// setTimeout(() => {
// wx.showToast({
// title: `发现${this.data.strangersCount}个附近的人`,
// icon: 'none',
// duration: 2000
// });
// }, 500);
},
// 显示好友位置
showFriendsLocation() {
// 切换到显示好友
this.setData({
currentFilter: 'friends'
});
wx.showToast({
title: `显示${this.data.friendsCount}个好友位置`,
icon: 'none',
duration: 2000
});
},
// 显示全部位置(好友和陌生人)
showAllLocations() {
// 切换到显示全部
this.setData({
currentFilter: 'all'
});
// 刷新附近用户数据
this.loadNearbyUsers();
// 延迟显示toast等待数据加载完成
setTimeout(() => {
wx.showToast({
title: `显示${this.data.friendsCount}个好友和${this.data.strangersCount}个附近的人`,
icon: 'none',
duration: 2000
});
}, 500);
},
// 🔥 ===== 数据更新方法 =====
// 更新未读消息数
updateUnreadMessageCount(count) {
this.setData({
unreadMessageCount: count || 0
});
},
// 更新好友请求数
updateFriendRequestCount(count) {
this.setData({
friendRequestCount: count || 0
});
},
// 更新附近的人数量
updateNearbyCount(count) {
this.setData({
nearbyCount: count || 0
});
},
// 更新在线状态
updateOnlineStatus(isOnline) {
this.setData({
isOnline: isOnline !== false
});
},
// 让地图相机完整显示以(lat, lng)为圆心radius为半径的圆
fitMapToCircle(lat, lng, radius) {
// 计算圆的四个边界点(上、下、左、右)
// 1度纬度约等于111km1度经度约等于111km*cos(纬度)
const latDelta = radius / 111000;
const lngDelta = radius / (111000 * Math.cos(lat * Math.PI / 180));
const points = [{
latitude: lat + latDelta,
longitude: lng
}, // 上
{
latitude: lat - latDelta,
longitude: lng
}, // 下
{
latitude: lat,
longitude: lng + lngDelta
}, // 右
{
latitude: lat,
longitude: lng - lngDelta
}, // 左
{
latitude: lat,
longitude: lng
} // 圆心
];
// padding自适应半径越大padding越小最小40最大100
let padding = Math.max(40, 120 - Math.round(radius / 10));
this.mapCtx && this.mapCtx.includePoints && this.mapCtx.includePoints({
points,
padding: [padding, padding, padding, padding]
});
},
// 保存POI提醒设置
onSavePoiRemind() {
wx.showToast({
title: '提醒设置已保存',
icon: 'success'
});
},
// 打开地点标记弹窗
onOpenLocationMarkModal() {
this.setData({
showLocationMarkModal: true
});
},
// 关闭地点标记弹窗
onCloseLocationMarkModal() {
this.setData({
showLocationMarkModal: false
});
},
// 筛选输入
onLocationMarkSearchInput(e) {
const text = e.detail.value.trim();
const list = this.data.locationMarkList.filter(item => item.name.includes(text));
this.setData({
locationMarkSearchText: text,
filteredLocationMarkList: list
});
},
// 删除按钮(静态演示)
onDeleteLocationMark(e) {
wx.showToast({
title: '删除演示',
icon: 'none'
});
},
// 修改按钮(静态演示)
onEditLocationMarkName(e) {
wx.showToast({
title: '修改名称演示',
icon: 'none'
});
},
// 设置提醒好友(静态演示)
onSetRemindFriends(e) {
wx.showToast({
title: '设置好友演示',
icon: 'none'
});
},
// 切换提醒类型(静态演示)
onToggleRemindType(e) {
wx.showToast({
title: '切换类型演示',
icon: 'none'
});
},
// POI提醒名称输入
onPoiRemindNameInput(e) {
const name = e.detail.value;
this.setData({
'lastPoiForRemind.name': name
});
},
// 地点标记列表项点击事件
onLocationMarkItemTap(e) {
const item = e.currentTarget.dataset.item;
this.setData({
showLocationMarkModal: false
});
const poi = {
detail: {
name: item.name,
address: item.address || '',
latitude: item.lat,
longitude: item.lng
}
};
this.onPoiTap(poi);
},
// 添加地点标记
onAddLocationPlace() {
// 纯定位版SDK不支持getPoiAround功能
wx.showModal({
title: '提示',
content: '该功能暂不可用',
showCancel: false
});
},
onPoiAroundItemTap(e) {
const item = e.currentTarget.dataset.item;
this.setData({
showPoiAroundModal: false
});
const poi = {
detail: {
name: item.name,
address: item.address || '',
latitude: item.latitude,
longitude: item.longitude
}
};
this.onPoiTap(poi);
},
onClosePoiAroundModal() {
this.setData({
showPoiAroundModal: false
});
},
closeMerchantInfo() {
this.setData({
merchantInfoModalVisible: false,
activeMerchantId: null
});
// 清除所有商户的active状态
this.updateMerchantActiveState(null);
},
// 更新商户active状态
updateMerchantActiveState(activeId) {
const markers = this.data.markers || [];
const updatedMarkers = markers.map(marker => {
if (marker.type === 'merchant') {
const markerBaseId = 10000;
const merchantId = marker.id - markerBaseId;
return {
...marker,
isActive: merchantId === activeId
};
}
return marker;
});
this.setData({
markers: updatedMarkers
});
},
preventClose(e) {
// 阻止事件冒泡,防止点击卡片内容时关闭弹窗
// 注意在微信小程序中使用catchtap已自动阻止事件冒泡不需要手动调用stopPropagation
// 此方法保留为空函数即可
},
// 点击"去"按钮,提示截图享优惠
onDishGoClick(e) {
console.log('点击了去按钮');
wx.showToast({
title: '截图享优惠',
icon: 'none',
duration: 2000
});
// 阻止事件冒泡,防止关闭弹窗
if (e && e.stopPropagation) {
e.stopPropagation();
}
},
onFavoriteMerchant() {
const merchant = this.data.selectedMerchant;
merchant.isFavorited = !merchant.isFavorited;
this.setData({
selectedMerchant: merchant,
merchantList: this.data.merchantList.map(m => m.id === merchant.id ? merchant : m)
});
// 可加toast提示
},
onNavigateMerchant() {
const merchant = this.data.selectedMerchant;
wx.openLocation({
latitude: merchant.latitude,
longitude: merchant.longitude,
name: merchant.name,
address: merchant.address,
scale: 16
});
},
//地点搜索结果的弹窗里的收藏
onAddressCollect() {
this.setData({
addressIsFavorited: !this.data.addressIsFavorited
})
const merchant = this.data.selectedMerchant;
const address = merchant.address;
const latitude = merchant.latitude;
const longitude = merchant.longitude;
const name = merchant.name;
if (this.data.placeMarkId == '') { //空 说明还没有收藏地址
this.onPoiFavoriteCommon(address, latitude, longitude, name);
} else { //说明刚才收藏了 再点击就是取消
this.onPoiCancelCommon(this.data.placeMarkId);
}
},
// 显示相机操作弹窗
showCameraActionSheet() {
this.setData({
showCameraAction: true
});
},
// 隐藏相机操作弹窗
hideCameraActionSheet() {
this.setData({
showCameraAction: false
});
},
ensureLoggedInForAction() {
if (this.data.isLoggedIn) {
return true;
}
wx.showToast({
title: '请先登录',
icon: 'none'
});
this.navigateToLogin();
return false;
},
// 导航到登录页面
navigateToLogin() {
wx.navigateTo({
url: '/pages/login/login'
});
}
});