Files
WoMenQuNaJu/cloudfunctions/calculateMeetSpot/index.js
2026-02-04 16:11:55 +08:00

153 lines
5.1 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.
// 云函数入口文件
const cloud = require('wx-server-sdk')
const axios = require('axios')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
const db = cloud.database()
const _ = db.command
exports.main = async (event, context) => {
const { roomId } = event
try {
// 1. 获取房间信息
const room = await db.collection('rooms').doc(roomId).get()
const data = room.data
if (!data) return { success: false, msg: '房间不存在' }
// 检查是否正在计算中(防并发)
if (data.status === 'calculating') {
return {
success: false,
msg: '正在计算中,请稍候...',
isCalculating: true
}
}
// 2. 提取有效坐标
const validMembers = data.members.filter(m => m.location && m.location.lat)
const locations = validMembers.map(m => ({
lng: m.location.lng,
lat: m.location.lat,
address: m.location.address || '',
name: m.location.name || ''
}))
// 验证至少需要2个位置才能计算
if (locations.length < 2) {
return { success: false, msg: '至少需要2人添加位置才能计算推荐地点' }
}
// 检查成员列表是否有变化(防止成员未变时重复计算)
if (data.status === 'calculated' && data.result && data.result.success) {
// 比较当前成员位置的数量和组成
const currentMemberIds = validMembers
.map(m => `${m.openid}_${m.location.lat}_${m.location.lng}`)
.sort()
.join(',')
// 存储上次计算时的成员快照
const lastMemberIds = data.lastCalculatedMembers || ''
if (currentMemberIds === lastMemberIds) {
return {
success: false,
msg: '成员位置未变化,无需重复计算',
isDuplicate: true,
existingResult: data.result
}
}
}
// 加锁:设置状态为计算中
await db.collection('rooms').doc(roomId).update({
data: {
status: _.set('calculating'),
calculateStartTime: _.set(db.serverDate())
}
})
console.log(`Room ${roomId} 状态已锁定为 calculating`)
// 3. 配置后端服务 URL请替换为实际部署的后端服务地址
// 示例:
// - 本地开发: http://localhost:8000
// - Render 部署: https://meetspot-xxx.onrender.com
// - Railway 部署: https://meetspot-production.railway.app
const BACKEND_URL = process.env.BACKEND_URL || 'https://meetspot.onrender.com'
console.log(`调用后端服务: ${BACKEND_URL}/api/miniprogram/calculate`)
// 4. 使用 HTTP 调用后端服务
const response = await axios.post(
`${BACKEND_URL}/api/miniprogram/calculate`,
{
locations: locations,
keywords: data.keywords || '咖啡馆',
requirements: data.requirements || ''
},
{
headers: {
'Content-Type': 'application/json'
},
timeout: 30000 // 30秒超时
}
)
const result = response.data
if (response.status !== 200 || !result) {
console.error('Backend Error:', response.status, result)
return { success: false, msg: '计算服务异常' }
}
// 5. 将结果回写到数据库
if (result.success) {
// 生成成员位置快照用于下次比对
const memberSnapshot = validMembers
.map(m => `${m.openid}_${m.location.lat}_${m.location.lng}`)
.sort()
.join(',')
await db.collection('rooms').doc(roomId).update({
data: {
result: _.set(result), // 使用 _.set 强制覆写 result 字段
status: _.set('calculated'), // 使用 _.set 强制覆写 status 字段
lastCalculateTime: _.set(db.serverDate()), // 记录计算时间
lastCalculatedMembers: _.set(memberSnapshot) // 记录成员快照
}
})
} else {
// 计算失败,释放锁
await db.collection('rooms').doc(roomId).update({
data: {
status: _.set('active')
}
})
}
return result
} catch (err) {
console.error('CalculateMeetSpot Error:', err)
// 发生异常时,释放锁
try {
await db.collection('rooms').doc(roomId).update({
data: {
status: _.set('active')
}
})
} catch (unlockErr) {
console.error('Failed to unlock room:', unlockErr)
}
return {
success: false,
msg: '计算失败',
error: err.message || err.toString()
}
}
}