接入自建后端 + 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
+414
View File
@@ -0,0 +1,414 @@
# 生日提醒小程序 - 云开发功能说明
## 📁 项目结构
```
生日提醒小程序/
├── cloudfunctions/ # 云函数目录
│ ├── login/ # 获取用户openid
│ │ ├── index.js
│ │ ├── config.json
│ │ └── package.json
│ ├── syncAnniversary/ # 同步纪念日数据
│ │ ├── index.js
│ │ ├── config.json
│ │ └── package.json
│ └── sendReminder/ # 发送提醒消息
│ ├── index.js
│ ├── config.json # 包含定时触发器配置
│ └── package.json
├── pages/ # 小程序页面
├── utils/ # 工具函数
├── app.js # 应用入口(已添加云开发初始化)
├── app.json # 应用配置
└── project.config.json # 项目配置
```
---
## 🔧 核心功能实现
### 1. 云开发初始化(app.js
```javascript
// 应用启动时初始化云开发
wx.cloud.init({
env: 'cloudbase-1gk3x0ia3a6b1f80',
traceUser: true
})
// 自动获取用户openid
await wx.cloud.callFunction({ name: 'login' })
```
**作用**
- 连接到你的云开发环境
- 获取用户唯一标识(openid
- 为后续功能提供基础
---
### 2. 订阅消息授权(add-anniversary.js
```javascript
// 用户添加纪念日并开启提醒时
wx.requestSubscribeMessage({
tmplIds: ['6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw']
})
```
**流程**
1. 用户添加纪念日
2. 开启"是否提醒"开关
3. 点击保存
4. 弹出订阅授权弹窗
5. 用户点击"允许"
6. 数据保存到本地和云端
**效果**
- ✅ 用户授权后才能收到推送
- ✅ 一次授权,长期有效
- ✅ 用户可随时管理订阅
---
### 3. 数据云端同步(syncAnniversary 云函数)
**支持的操作**
#### 添加纪念日
```javascript
wx.cloud.callFunction({
name: 'syncAnniversary',
data: {
action: 'add',
data: { ...anniversaryData }
}
})
```
#### 更新纪念日
```javascript
wx.cloud.callFunction({
name: 'syncAnniversary',
data: {
action: 'update',
data: { id, ...anniversaryData }
}
})
```
#### 删除纪念日
```javascript
wx.cloud.callFunction({
name: 'syncAnniversary',
data: {
action: 'delete',
data: { id }
}
})
```
**数据结构**
```javascript
{
_id: "cloud-generated-id",
_openid: "user-openid", // 自动添加
personId: "person-id",
personName: "张三",
type: "birthday",
solarYear: 1990,
solarMonth: 5,
solarDay: 15,
remindEnabled: true,
remindDays: 7,
remark: "记得买蛋糕",
createTime: Date,
updateTime: Date
}
```
---
### 4. 定时发送提醒(sendReminder 云函数)
**执行时间**:每天上午9:00
**执行流程**
```
1. 查询所有启用提醒的纪念日
2. 遍历每个纪念日
3. 计算距离纪念日还有多少天
4. 判断是否需要提醒
- 当天生日:发送
- 提前N天:发送(N=用户设置的remindDays
5. 检查今天是否已发送
6. 调用微信API发送订阅消息
7. 记录提醒日志
```
**提醒内容示例**
```
称呼:张三
临近日期:还有3天
生日日期:2025年10月30日
温馨提示:别忘了准备一份礼物哦!
```
**日志记录**
```javascript
{
anniversaryId: "anniversary-id",
personName: "张三",
typeName: "公历生日",
daysUntil: 3,
sendDate: Date,
status: "success" // 或 "failed"
}
```
---
## 🔄 数据流程图
### 用户添加纪念日
```
用户填写表单
开启提醒开关
点击保存
[请求订阅授权] ← 用户授权
保存到本地存储
同步到云数据库 ← 包含 openid
完成
```
### 定时提醒流程
```
每天 9:00
云函数被触发
查询云数据库
筛选需要提醒的纪念日
循环处理每条记录
计算剩余天数
满足条件?
├─ 是 → 发送订阅消息 → 记录日志
└─ 否 → 跳过
完成
```
---
## 🎯 关键技术点
### 1. openid 的作用
```javascript
// openid 是用户在你的小程序中的唯一标识
{
"_openid": "oABCD1234567890", // 自动添加到数据库记录
"personName": "张三",
...
}
```
**用途**
- 区分不同用户的数据
- 发送订阅消息时指定接收者
- 保证数据安全(用户只能访问自己的数据)
### 2. 订阅消息模板
**你的模板信息**
```
模板ID: 6J7Stt-lu7DKU6jblJ0nZGq_D81z5glnksf7qWfy5Yw
字段映射:
- name1.DATA → 称呼(人员姓名)
- thing2.DATA → 临近日期(还有X天)
- thing6.DATA → 生日日期(2025年10月30日)
- thing5.DATA → 温馨提示(备注或默认文案)
```
### 3. 定时触发器
**Cron 表达式**`0 0 9 * * * *`
```
秒 分 时 日 月 星期 年
0 0 9 * * * *
含义:每天上午9点0分0秒执行
```
**修改提醒时间**
```
每天早上8点: 0 0 8 * * * *
每天晚上8点: 0 0 20 * * * *
每天早晚两次: 0 0 8,20 * * * *
```
---
## 📊 数据库设计
### anniversaries(纪念日表)
| 字段 | 类型 | 说明 | 示例 |
|------|------|------|------|
| _id | String | 主键(自动生成) | "5f1e..." |
| _openid | String | 用户openid(自动) | "oABC..." |
| personId | String | 人员ID | "id_123..." |
| personName | String | 人员姓名 | "张三" |
| type | String | 类型 | "birthday" |
| solarMonth | Number | 公历月份 | 10 |
| solarDay | Number | 公历日期 | 30 |
| remindEnabled | Boolean | 是否提醒 | true |
| remindDays | Number | 提前天数 | 7 |
| remark | String | 备注 | "买蛋糕" |
### remind_logs(提醒日志表)
| 字段 | 类型 | 说明 | 示例 |
|------|------|------|------|
| _id | String | 主键(自动生成) | "5f1e..." |
| anniversaryId | String | 纪念日ID | "5f1e..." |
| personName | String | 人员姓名 | "张三" |
| daysUntil | Number | 剩余天数 | 3 |
| sendDate | Date | 发送时间 | Date对象 |
| status | String | 状态 | "success" |
---
## 🚨 注意事项
### 1. 订阅消息限制
- ✅ 用户主动触发授权(不能自动弹出)
- ✅ 一次授权一个模板
- ✅ 用户可以随时取消订阅
- ❌ 不能发送营销类消息
### 2. 云函数限制
**免费额度**(每天):
- 调用次数:10万次
- 运行时间:40万GBs
- 出流量:5GB
**对于个人用户,完全够用!**
### 3. 数据库限制
**免费额度**
- 容量:5GB
- 读操作:5万次/天
- 写操作:3万次/天
**估算**
- 100个用户,每人10条纪念日 = 1000条记录
- 每条约1KB,总共约1MB
- 完全在免费额度内!
---
## 🔍 调试技巧
### 1. 查看云函数日志
```
云开发控制台 → 云函数 → 选择函数 → 日志
```
**可以看到**
- 函数执行时间
- 返回结果
- 错误信息
- console.log 输出
### 2. 测试云函数
```
云开发控制台 → 云函数 → 选择函数 → 测试
输入测试参数:{}
点击"运行测试"
```
### 3. 查看数据库
```
云开发控制台 → 数据库 → 选择集合
可以:
- 查看所有记录
- 编辑数据
- 删除数据
- 导出数据
```
### 4. 模拟定时触发
```javascript
// 临时修改 Cron 表达式为每分钟执行
"0 */1 * * * * *"
// 测试完成后改回
"0 0 9 * * * *"
```
---
## 💡 优化建议
### 1. 添加提醒历史页面
显示用户收到的所有提醒记录。
### 2. 支持多个提醒时间
比如提前7天、3天、当天各提醒一次。
### 3. 自定义提醒文案
让用户可以自定义温馨提示内容。
### 4. 提醒统计
显示总共发送了多少条提醒,成功率等。
---
## 🎉 总结
现在你的小程序具备了完整的云端能力:
**数据云端存储** - 永不丢失
**自动推送提醒** - 不再遗忘
**多设备同步** - 随处访问
**安全可靠** - openid隔离
**开始享受智能生日提醒服务吧!** 🎂