Files
everything-is-suitable/everything-is-suitable-uniapp/cloudfunctions/dailyPush/index.js
T
zhangxiang bd4a8aa358 feat(cloud): 实现微信云函数 - 订阅管理与每日运势推送
- subscribe: 用户订阅/取消订阅/查询订阅状态
- daily-push: 定时查询订阅用户、生成运势、发送订阅消息
- push-test: 推送调试云函数
- 定时触发器配置,每日 7:00/12:00/18:00 推送
2026-08-13 08:06:10 +08:00

142 lines
4.2 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.
// 云函数:dailyPush
// 每日定时推送运势通知
// 定时触发器:cron: 0 0 7 * * * *(每日 07:00
// 或每分钟扫描:cron: 0 * * * * * *(支持用户自定义时间)
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
const db = cloud.database()
// 引入共享算法包(需在云函数部署时安装)
// 由于云函数环境限制,算法代码会内联到本文件
// 参见 _algorithm.js 文件
const _ = require('./_algorithm')
exports.main = async (event, context) => {
const now = new Date()
const todayStr = now.toISOString().slice(0, 10)
const currentHour = now.getHours()
const currentMinute = now.getMinutes()
console.log(`[dailyPush] Triggered at ${now.toISOString()}`)
try {
// 查询所有已开启推送的订阅
const { data: subscriptions } = await db.collection('subscriptions')
.where({
pushEnabled: true,
})
.get()
console.log(`[dailyPush] Found ${subscriptions.length} active subscriptions`)
let pushCount = 0
let skipCount = 0
let errorCount = 0
for (const sub of subscriptions) {
try {
// 检查是否已达到推送时间
const [pushHour, pushMinute] = (sub.pushTime || '07:00').split(':').map(Number)
if (currentHour !== pushHour || currentMinute !== pushMinute) {
skipCount++
continue
}
// 检查是否已推送过(防重复)
if (sub.lastPushDate === todayStr) {
skipCount++
continue
}
// 生成运势内容
const fortune = _.generatePushContent(sub.birthInfo, now)
// 格式化推送内容
const pushData = {
touser: sub.openid,
templateId: sub.templateId,
page: '/pages/fortune/index', // 点击跳转到运势页面
data: {
date1: { value: formatDate(now) },
thing2: { value: `综合运势评分${fortune.overallScore}分,等级:${fortune.overallLuck}` },
thing3: { value: formatFortuneSummary(fortune) },
thing4: { value: `幸运色:${fortune.luckyColor} 幸运数字:${fortune.luckyNumber}` },
},
}
// 发送微信订阅消息
await cloud.openapi.subscribeMessage.send(pushData)
// 更新最后推送日期
await db.collection('subscriptions').doc(sub._id).update({
data: { lastPushDate: todayStr },
})
pushCount++
console.log(`[dailyPush] Pushed to ${sub.openid}`)
} catch (err) {
errorCount++
console.error(`[dailyPush] Failed for ${sub.openid}:`, err.message)
}
}
return {
success: true,
summary: {
total: subscriptions.length,
pushed: pushCount,
skipped: skipCount,
errors: errorCount,
},
}
} catch (err) {
console.error('[dailyPush] Fatal error:', err)
return { success: false, error: err.message }
}
}
/**
* 格式化日期为中文显示
*/
function formatDate(date) {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const weekdays = ['日', '一', '二', '三', '四', '五', '六']
const weekday = weekdays[date.getDay()]
return `${year}${month}${day}日 星期${weekday}`
}
/**
* 格式化运势摘要
*/
function formatFortuneSummary(fortune) {
const parts = []
if (fortune.careerAdvice) {
const brief = fortune.careerAdvice.length > 10
? fortune.careerAdvice.slice(0, 10) + '…'
: fortune.careerAdvice
parts.push(`事业:${brief}`)
}
if (fortune.wealthAdvice) {
const brief = fortune.wealthAdvice.length > 10
? fortune.wealthAdvice.slice(0, 10) + '…'
: fortune.wealthAdvice
parts.push(`财运:${brief}`)
}
if (fortune.relationshipAdvice) {
const brief = fortune.relationshipAdvice.length > 10
? fortune.relationshipAdvice.slice(0, 10) + '…'
: fortune.relationshipAdvice
parts.push(`感情:${brief}`)
}
if (fortune.healthAdvice) {
const brief = fortune.healthAdvice.length > 10
? fortune.healthAdvice.slice(0, 10) + '…'
: fortune.healthAdvice
parts.push(`健康:${brief}`)
}
return parts.join(' ')
}