const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const db = cloud.database() const _ = db.command // 粗略经纬度范围换算(1度≈111km) function latDelta(km) { return km / 111 } function lngDelta(km, lat) { return km / (111 * Math.cos(lat * Math.PI / 180)) } function calcDistance(lat1, lng1, lat2, lng2) { const R = 6371 const dLat = (lat2 - lat1) * Math.PI / 180 const dLng = (lng2 - lng1) * Math.PI / 180 const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLng / 2) ** 2 return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) * 1000 // meters } exports.main = async (event, context) => { const { OPENID } = cloud.getWXContext() const { latitude, longitude, radiusKm = 5 } = event if (!latitude || !longitude) { return { code: -1, message: '缺少位置信息' } } // 在线判断:60秒内更新过位置的用户为在线 const onlineThreshold = new Date(Date.now() - 60 * 1000).toISOString() try { const dLat = latDelta(radiusKm) const dLng = lngDelta(radiusKm, latitude) const usersRes = await db.collection('users') .where( _.and([ { openid: _.neq(OPENID) }, // 排除自己 { 'lastLocation.latitude': _.gt(latitude - dLat).and(_.lt(latitude + dLat)) }, { 'lastLocation.longitude': _.gt(longitude - dLng).and(_.lt(longitude + dLng)) }, { pets: _.exists(true) }, ]) ) .field({ openid: true, nickName: true, avatarUrl: true, lastLocation: true, lastSeen: true, isOnline: true, pets: true, location: true, bio: true, }) .limit(30) .get() const nearby = usersRes.data .map(user => { const userLat = user.lastLocation?.latitude const userLng = user.lastLocation?.longitude if (!userLat || !userLng) return null const distance = calcDistance(latitude, longitude, userLat, userLng) if (distance > radiusKm * 1000) return null return { userId: user.openid, user, pet: user.pets?.[0] || null, distance, isOnline: user.isOnline && user.lastSeen > onlineThreshold, location: { latitude: userLat, longitude: userLng }, } }) .filter(Boolean) .sort((a, b) => a.distance - b.distance) return { code: 0, data: nearby } } catch (e) { return { code: -1, message: e.message } } }