- 新增 server/:Node + Express + SQLite + node-cron 实现登录、纪念日 CRUD 和定时订阅消息推送 - 新增 .gitea/workflows/deploy.yml:推送即触发群晖 Docker 部署,监听 15002 - utils/api.js:自动按 envVersion 切换本地/线上 BASE_URL - app.js 与 add-anniversary.js 移除 wx.cloud 调用,改走自建后端 - cloudfunctions/ 暂保留以便回滚 - 一并提交此前未入库的首页 / 设置页 / 日历 / 万年历等改造 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"permissions": {
|
||||
"openapi": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// 云函数:获取用户openid
|
||||
const cloud = require('wx-server-sdk')
|
||||
|
||||
cloud.init({
|
||||
env: cloud.DYNAMIC_CURRENT_ENV
|
||||
})
|
||||
|
||||
exports.main = async (event, context) => {
|
||||
const wxContext = cloud.getWXContext()
|
||||
|
||||
return {
|
||||
openid: wxContext.OPENID,
|
||||
appid: wxContext.APPID,
|
||||
unionid: wxContext.UNIONID,
|
||||
env: wxContext.ENV
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "login",
|
||||
"version": "1.0.0",
|
||||
"description": "获取用户openid",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"wx-server-sdk": "~2.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"permissions": {
|
||||
"openapi": [
|
||||
"subscribeMessage.send"
|
||||
]
|
||||
},
|
||||
"triggers": [
|
||||
{
|
||||
"name": "dailyReminder",
|
||||
"type": "timer",
|
||||
"config": "0 0 9 * * * *"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
// 云函数:发送生日提醒
|
||||
const cloud = require('wx-server-sdk')
|
||||
|
||||
cloud.init({
|
||||
env: cloud.DYNAMIC_CURRENT_ENV
|
||||
})
|
||||
|
||||
const db = cloud.database()
|
||||
|
||||
// 模板ID
|
||||
const TEMPLATE_ID = '6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw'
|
||||
|
||||
/**
|
||||
* 计算两个日期之间的天数差
|
||||
*/
|
||||
function getDaysUntil(targetDate) {
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
|
||||
const target = new Date(targetDate)
|
||||
target.setHours(0, 0, 0, 0)
|
||||
|
||||
const diffTime = target - today
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
|
||||
|
||||
return diffDays
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
*/
|
||||
function formatDate(date) {
|
||||
const d = new Date(date)
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${year}年${month}月${day}日`
|
||||
}
|
||||
|
||||
const TYPE_NAMES = {
|
||||
birthday: '公历生日',
|
||||
lunar_birthday: '农历生日',
|
||||
wedding: '结婚纪念日',
|
||||
engagement: '订婚纪念日',
|
||||
other: '其他纪念日'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型名称
|
||||
*/
|
||||
function getTypeName(type, customName) {
|
||||
if (type === 'other' && customName) return customName
|
||||
return TYPE_NAMES[type] || '纪念日'
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取今年的纪念日日期
|
||||
*/
|
||||
function getThisYearDate(anniversary) {
|
||||
const today = new Date()
|
||||
const currentYear = today.getFullYear()
|
||||
|
||||
// 使用公历日期计算
|
||||
let thisYearDate = new Date(currentYear, anniversary.solarMonth - 1, anniversary.solarDay)
|
||||
|
||||
// 如果今年的已经过了,计算明年的
|
||||
const daysUntil = getDaysUntil(thisYearDate)
|
||||
if (daysUntil < 0) {
|
||||
thisYearDate = new Date(currentYear + 1, anniversary.solarMonth - 1, anniversary.solarDay)
|
||||
}
|
||||
|
||||
return thisYearDate
|
||||
}
|
||||
|
||||
/**
|
||||
* 主函数
|
||||
*/
|
||||
exports.main = async (event, context) => {
|
||||
console.log('开始执行提醒任务...')
|
||||
|
||||
try {
|
||||
// 获取所有启用提醒的纪念日
|
||||
const anniversariesRes = await db.collection('anniversaries')
|
||||
.where({
|
||||
remindEnabled: true
|
||||
})
|
||||
.get()
|
||||
|
||||
console.log(`找到 ${anniversariesRes.data.length} 条启用提醒的纪念日`)
|
||||
|
||||
let successCount = 0
|
||||
let failCount = 0
|
||||
|
||||
// 遍历每个纪念日
|
||||
for (const anniversary of anniversariesRes.data) {
|
||||
try {
|
||||
// 计算今年的纪念日日期
|
||||
const thisYearDate = getThisYearDate(anniversary)
|
||||
const daysUntil = getDaysUntil(thisYearDate)
|
||||
|
||||
console.log(`${anniversary.personName} 的 ${getTypeName(anniversary.type, anniversary.customTypeName)},还有 ${daysUntil} 天`)
|
||||
|
||||
// 判断是否需要提醒
|
||||
const shouldRemind = (
|
||||
daysUntil === 0 || // 当天
|
||||
daysUntil === anniversary.remindDays // 提前N天
|
||||
)
|
||||
|
||||
if (shouldRemind) {
|
||||
// 检查今天是否已经发送过提醒
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
|
||||
const logRes = await db.collection('remind_logs')
|
||||
.where({
|
||||
anniversaryId: anniversary._id,
|
||||
sendDate: db.command.gte(today)
|
||||
})
|
||||
.count()
|
||||
|
||||
if (logRes.total > 0) {
|
||||
console.log(`今天已发送过提醒,跳过: ${anniversary.personName}`)
|
||||
continue
|
||||
}
|
||||
|
||||
// 发送订阅消息
|
||||
const sendRes = await cloud.openapi.subscribeMessage.send({
|
||||
touser: anniversary.openid,
|
||||
page: 'pages/index/index',
|
||||
data: {
|
||||
name1: {
|
||||
value: anniversary.personName
|
||||
},
|
||||
thing2: {
|
||||
value: daysUntil === 0 ? '今天' : `还有${daysUntil}天`
|
||||
},
|
||||
thing6: {
|
||||
value: formatDate(thisYearDate)
|
||||
},
|
||||
thing5: {
|
||||
value: anniversary.remark || '别忘了准备一份礼物哦!'
|
||||
}
|
||||
},
|
||||
templateId: TEMPLATE_ID,
|
||||
miniprogramState: 'formal' // 正式版
|
||||
})
|
||||
|
||||
console.log(`发送成功: ${anniversary.personName}`, sendRes)
|
||||
|
||||
// 记录提醒日志
|
||||
await db.collection('remind_logs').add({
|
||||
data: {
|
||||
anniversaryId: anniversary._id,
|
||||
personName: anniversary.personName,
|
||||
typeName: getTypeName(anniversary.type, anniversary.customTypeName),
|
||||
daysUntil: daysUntil,
|
||||
sendDate: new Date(),
|
||||
status: 'success'
|
||||
}
|
||||
})
|
||||
|
||||
successCount++
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`发送失败: ${anniversary.personName}`, err)
|
||||
failCount++
|
||||
|
||||
// 记录失败日志
|
||||
await db.collection('remind_logs').add({
|
||||
data: {
|
||||
anniversaryId: anniversary._id,
|
||||
personName: anniversary.personName,
|
||||
sendDate: new Date(),
|
||||
status: 'failed',
|
||||
error: err.message
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`提醒任务完成: 成功${successCount}条,失败${failCount}条`)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
total: anniversariesRes.data.length,
|
||||
successCount,
|
||||
failCount
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('提醒任务执行失败:', err)
|
||||
return {
|
||||
success: false,
|
||||
error: err.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1525
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "sendReminder",
|
||||
"version": "1.0.0",
|
||||
"description": "发送生日提醒订阅消息",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"wx-server-sdk": "~2.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"permissions": {
|
||||
"openapi": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
// 云函数:同步纪念日数据到云端
|
||||
const cloud = require('wx-server-sdk')
|
||||
|
||||
cloud.init({
|
||||
env: cloud.DYNAMIC_CURRENT_ENV
|
||||
})
|
||||
|
||||
const db = cloud.database()
|
||||
|
||||
exports.main = async (event, context) => {
|
||||
const wxContext = cloud.getWXContext()
|
||||
const openid = wxContext.OPENID
|
||||
|
||||
const { action, data } = event
|
||||
|
||||
try {
|
||||
switch (action) {
|
||||
case 'add':
|
||||
// 添加纪念日
|
||||
return await addAnniversary(openid, data)
|
||||
|
||||
case 'update':
|
||||
// 更新纪念日
|
||||
return await updateAnniversary(openid, data)
|
||||
|
||||
case 'delete':
|
||||
// 删除纪念日
|
||||
return await deleteAnniversary(openid, data.id)
|
||||
|
||||
case 'sync':
|
||||
// 批量同步
|
||||
return await syncAnniversaries(openid, data)
|
||||
|
||||
case 'get':
|
||||
// 获取用户所有纪念日
|
||||
return await getAnniversaries(openid)
|
||||
|
||||
default:
|
||||
return {
|
||||
success: false,
|
||||
error: '未知操作'
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('操作失败:', err)
|
||||
return {
|
||||
success: false,
|
||||
error: err.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加纪念日
|
||||
*/
|
||||
async function addAnniversary(openid, anniversary) {
|
||||
const res = await db.collection('anniversaries').add({
|
||||
data: {
|
||||
...anniversary,
|
||||
openid,
|
||||
createTime: db.serverDate(),
|
||||
updateTime: db.serverDate()
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
id: res._id
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新纪念日
|
||||
*/
|
||||
async function updateAnniversary(openid, anniversary) {
|
||||
const { id, ...updateData } = anniversary
|
||||
|
||||
await db.collection('anniversaries')
|
||||
.where({
|
||||
_id: id,
|
||||
openid
|
||||
})
|
||||
.update({
|
||||
data: {
|
||||
...updateData,
|
||||
updateTime: db.serverDate()
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
success: true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除纪念日
|
||||
*/
|
||||
async function deleteAnniversary(openid, id) {
|
||||
await db.collection('anniversaries')
|
||||
.where({
|
||||
_id: id,
|
||||
openid
|
||||
})
|
||||
.remove()
|
||||
|
||||
return {
|
||||
success: true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量同步纪念日
|
||||
*/
|
||||
async function syncAnniversaries(openid, anniversaries) {
|
||||
// 先删除用户的所有纪念日
|
||||
await db.collection('anniversaries')
|
||||
.where({
|
||||
openid
|
||||
})
|
||||
.remove()
|
||||
|
||||
// 批量添加
|
||||
const tasks = anniversaries.map(anniversary => {
|
||||
return db.collection('anniversaries').add({
|
||||
data: {
|
||||
...anniversary,
|
||||
openid,
|
||||
createTime: db.serverDate(),
|
||||
updateTime: db.serverDate()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
await Promise.all(tasks)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
count: anniversaries.length
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户所有纪念日
|
||||
*/
|
||||
async function getAnniversaries(openid) {
|
||||
const res = await db.collection('anniversaries')
|
||||
.where({
|
||||
openid
|
||||
})
|
||||
.get()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: res.data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "syncAnniversary",
|
||||
"version": "1.0.0",
|
||||
"description": "同步纪念日数据",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"wx-server-sdk": "~2.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user