接入自建后端 + Gitea CI/CD
部署到群晖 / deploy (push) Failing after 6m22s

- 新增 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:
yuming
2026-06-01 15:44:09 +08:00
parent 6747ade9c4
commit 3965e542fc
49 changed files with 5616 additions and 670 deletions
+6
View File
@@ -0,0 +1,6 @@
{
"permissions": {
"openapi": []
}
}
+18
View File
@@ -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
}
}
+10
View File
@@ -0,0 +1,10 @@
{
"name": "login",
"version": "1.0.0",
"description": "获取用户openid",
"main": "index.js",
"dependencies": {
"wx-server-sdk": "~2.6.3"
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"permissions": {
"openapi": [
"subscribeMessage.send"
]
},
"triggers": [
{
"name": "dailyReminder",
"type": "timer",
"config": "0 0 9 * * * *"
}
]
}
+197
View File
@@ -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
}
}
}
File diff suppressed because it is too large Load Diff
+10
View File
@@ -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": []
}
}
+157
View File
@@ -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"
}
}