实现了包含药物信息管理、服药记录追踪、统计分析、自动状态更新和推送提醒的完整药物管理系统。 核心功能: - 药物 CRUD 操作,支持多种剂型和自定义服药时间 - 惰性生成服药记录策略,查询时才生成当天记录 - 定时任务自动更新过期记录状态(每30分钟) - 服药前15分钟自动推送提醒(每5分钟检查) - 每日/范围/总体统计分析功能 - 完整的 API 文档和数据库建表脚本 技术实现: - 使用 Sequelize ORM 管理 MySQL 数据表 - 集成 @nestjs/schedule 实现定时任务 - 复用现有推送通知系统发送提醒 - 采用软删除和权限验证保障数据安全
380 lines
7.6 KiB
Markdown
380 lines
7.6 KiB
Markdown
# 药物管理模块
|
||
|
||
## 概述
|
||
|
||
药物管理模块提供完整的用药提醒和服药记录管理功能,包括:
|
||
|
||
- 药物信息管理(CRUD)
|
||
- 服药记录追踪
|
||
- 统计分析
|
||
- 自动状态更新
|
||
- 推送提醒
|
||
|
||
## 功能特性
|
||
|
||
### 1. 药物管理
|
||
|
||
- 支持多种药物剂型(胶囊、药片、注射、喷雾、滴剂、糖浆等)
|
||
- 灵活的服药时间设置
|
||
- 支持每日重复模式
|
||
- 可设置开始和结束日期
|
||
- 支持添加药物照片和备注
|
||
|
||
### 2. 服药记录
|
||
|
||
- **惰性生成策略**:查询时才生成当天记录,避免预先生成大量数据
|
||
- 四种状态:待服用(upcoming)、已服用(taken)、已错过(missed)、已跳过(skipped)
|
||
- 自动状态更新:定时任务每30分钟检查并更新过期记录
|
||
- 支持标记服用、跳过服药、更新记录
|
||
|
||
### 3. 统计功能
|
||
|
||
- 每日统计:计划服药次数、已服用、已错过、待服用、完成率
|
||
- 日期范围统计:支持查询任意时间段的统计数据
|
||
- 总体统计概览:总记录数、完成率等
|
||
|
||
### 4. 推送提醒
|
||
|
||
- 定时任务每5分钟检查即将到来的服药时间(提前15-20分钟)
|
||
- 集成现有推送通知系统
|
||
- 支持自定义提醒消息
|
||
|
||
## API 接口
|
||
|
||
### 药物管理接口
|
||
|
||
#### 1. 获取药物列表
|
||
|
||
```http
|
||
GET /medications?isActive=true&page=1&pageSize=20
|
||
```
|
||
|
||
#### 2. 创建药物
|
||
|
||
```http
|
||
POST /medications
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "Metformin",
|
||
"photoUrl": "https://cdn.example.com/med_001.jpg",
|
||
"form": "capsule",
|
||
"dosageValue": 1,
|
||
"dosageUnit": "粒",
|
||
"timesPerDay": 2,
|
||
"medicationTimes": ["08:00", "20:00"],
|
||
"repeatPattern": "daily",
|
||
"startDate": "2025-01-01T00:00:00.000Z",
|
||
"note": "饭后服用"
|
||
}
|
||
```
|
||
|
||
#### 3. 更新药物
|
||
|
||
```http
|
||
PUT /medications/{id}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"dosageValue": 2,
|
||
"timesPerDay": 3,
|
||
"medicationTimes": ["08:00", "14:00", "20:00"]
|
||
}
|
||
```
|
||
|
||
#### 4. 删除药物
|
||
|
||
```http
|
||
DELETE /medications/{id}
|
||
```
|
||
|
||
#### 5. 停用药物
|
||
|
||
```http
|
||
POST /medications/{id}/deactivate
|
||
```
|
||
|
||
### 服药记录接口
|
||
|
||
#### 1. 获取服药记录
|
||
|
||
```http
|
||
GET /medication-records?date=2025-01-15&status=upcoming
|
||
```
|
||
|
||
#### 2. 获取今日服药记录
|
||
|
||
```http
|
||
GET /medication-records/today
|
||
```
|
||
|
||
#### 3. 标记为已服用
|
||
|
||
```http
|
||
POST /medication-records/{recordId}/take
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"actualTime": "2025-01-15T08:10:00.000Z"
|
||
}
|
||
```
|
||
|
||
#### 4. 跳过服药
|
||
|
||
```http
|
||
POST /medication-records/{recordId}/skip
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"note": "今天状态不好,暂时跳过"
|
||
}
|
||
```
|
||
|
||
#### 5. 更新服药记录
|
||
|
||
```http
|
||
PUT /medication-records/{recordId}
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"status": "taken",
|
||
"actualTime": "2025-01-15T08:15:00.000Z",
|
||
"note": "延迟服用"
|
||
}
|
||
```
|
||
|
||
### 统计接口
|
||
|
||
#### 1. 获取每日统计
|
||
|
||
```http
|
||
GET /medication-stats/daily?date=2025-01-15
|
||
```
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "查询成功",
|
||
"data": {
|
||
"date": "2025-01-15",
|
||
"totalScheduled": 6,
|
||
"taken": 4,
|
||
"missed": 1,
|
||
"upcoming": 1,
|
||
"completionRate": 66.67
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. 获取日期范围统计
|
||
|
||
```http
|
||
GET /medication-stats/range?startDate=2025-01-01&endDate=2025-01-15
|
||
```
|
||
|
||
#### 3. 获取总体统计
|
||
|
||
```http
|
||
GET /medication-stats/overall
|
||
```
|
||
|
||
## 数据模型
|
||
|
||
### Medication(药物)
|
||
|
||
```typescript
|
||
{
|
||
id: string;
|
||
userId: string;
|
||
name: string; // 药物名称
|
||
photoUrl?: string; // 药物照片
|
||
form: MedicationForm; // 剂型
|
||
dosageValue: number; // 剂量数值
|
||
dosageUnit: string; // 剂量单位
|
||
timesPerDay: number; // 每日服用次数
|
||
medicationTimes: string[]; // 服药时间
|
||
repeatPattern: RepeatPattern;
|
||
startDate: Date;
|
||
endDate?: Date;
|
||
note?: string;
|
||
isActive: boolean;
|
||
createdAt: Date;
|
||
updatedAt: Date;
|
||
}
|
||
```
|
||
|
||
### MedicationRecord(服药记录)
|
||
|
||
```typescript
|
||
{
|
||
id: string;
|
||
medicationId: string;
|
||
userId: string;
|
||
scheduledTime: Date; // 计划服药时间
|
||
actualTime?: Date; // 实际服药时间
|
||
status: MedicationStatus;
|
||
note?: string;
|
||
createdAt: Date;
|
||
updatedAt: Date;
|
||
}
|
||
```
|
||
|
||
## 业务逻辑说明
|
||
|
||
### 1. 惰性生成策略
|
||
|
||
服药记录采用惰性生成策略,而非预先生成大量记录:
|
||
|
||
```typescript
|
||
// 查询记录时自动生成当天记录
|
||
async findAll(userId: string, query: MedicationRecordQueryDto) {
|
||
// 1. 确保指定日期的记录存在
|
||
await this.recordGenerator.ensureRecordsExist(userId, query.date);
|
||
|
||
// 2. 查询并返回记录
|
||
return this.recordModel.findAll({...});
|
||
}
|
||
```
|
||
|
||
### 2. 状态自动更新
|
||
|
||
定时任务每30分钟检查并更新过期记录:
|
||
|
||
```typescript
|
||
@Cron(CronExpression.EVERY_30_MINUTES)
|
||
async updateExpiredRecords() {
|
||
// 将已过期的 upcoming 记录更新为 missed
|
||
await this.recordModel.update(
|
||
{ status: MedicationStatusEnum.MISSED },
|
||
{
|
||
where: {
|
||
status: MedicationStatusEnum.UPCOMING,
|
||
scheduledTime: { [Op.lt]: new Date() }
|
||
}
|
||
}
|
||
);
|
||
}
|
||
```
|
||
|
||
### 3. 推送提醒
|
||
|
||
定时任务每5分钟检查即将到来的服药时间:
|
||
|
||
```typescript
|
||
@Cron('*/5 * * * *')
|
||
async checkAndSendReminders() {
|
||
const now = new Date();
|
||
const reminderStart = dayjs(now).add(15, 'minute').toDate();
|
||
const reminderEnd = dayjs(now).add(20, 'minute').toDate();
|
||
|
||
// 查找15-20分钟后需要服药的记录
|
||
const upcomingRecords = await this.recordModel.findAll({
|
||
where: {
|
||
status: MedicationStatusEnum.UPCOMING,
|
||
scheduledTime: { [Op.between]: [reminderStart, reminderEnd] }
|
||
}
|
||
});
|
||
|
||
// 发送推送通知
|
||
for (const record of upcomingRecords) {
|
||
await this.sendReminder(record);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 部署说明
|
||
|
||
### 1. 执行数据库迁移
|
||
|
||
```bash
|
||
# 连接到 MySQL 数据库
|
||
mysql -u your_username -p your_database
|
||
|
||
# 执行建表 SQL
|
||
source sql-scripts/medications-tables-create.sql
|
||
```
|
||
|
||
### 2. 环境变量
|
||
|
||
确保 `.env` 文件中包含以下配置:
|
||
|
||
```env
|
||
# 数据库配置
|
||
DB_HOST=localhost
|
||
DB_PORT=3306
|
||
DB_USERNAME=your_username
|
||
DB_PASSWORD=your_password
|
||
DB_DATABASE=pilates_db
|
||
|
||
# JWT 配置
|
||
JWT_SECRET=your_jwt_secret
|
||
|
||
# 推送通知配置(如需使用推送功能)
|
||
APPLE_KEY_ID=your_apple_key_id
|
||
APPLE_ISSUER_ID=your_apple_issuer_id
|
||
APPLE_PRIVATE_KEY_PATH=path/to/private/key.p8
|
||
```
|
||
|
||
### 3. 启动应用
|
||
|
||
```bash
|
||
# 开发模式
|
||
yarn start:dev
|
||
|
||
# 生产模式
|
||
yarn build
|
||
yarn start:prod
|
||
```
|
||
|
||
## 测试建议
|
||
|
||
### 1. 基础功能测试
|
||
|
||
- 创建药物
|
||
- 查询药物列表
|
||
- 更新药物信息
|
||
- 删除/停用药物
|
||
|
||
### 2. 记录管理测试
|
||
|
||
- 查询今日记录(验证惰性生成)
|
||
- 标记服用
|
||
- 跳过服药
|
||
- 更新记录
|
||
|
||
### 3. 统计功能测试
|
||
|
||
- 每日统计计算准确性
|
||
- 日期范围统计
|
||
- 完成率计算
|
||
|
||
### 4. 定时任务测试
|
||
|
||
- 状态自动更新(等待30分钟后检查)
|
||
- 推送提醒发送(创建15分钟后的服药记录)
|
||
|
||
## 注意事项
|
||
|
||
1. **时区处理**:所有时间使用 UTC 存储,前端需要转换为本地时间
|
||
2. **权限控制**:所有接口需要 JWT 认证,用户只能访问自己的数据
|
||
3. **惰性生成**:首次查询某天记录时会自动生成,可能有轻微延迟
|
||
4. **定时任务**:依赖 `@nestjs/schedule` 模块,确保已启用
|
||
5. **推送通知**:需要正确配置 APNs 证书和密钥
|
||
|
||
## 未来扩展
|
||
|
||
1. **周计划模式**:支持每周特定日期服药
|
||
2. **自定义周期**:支持间隔天数服药(如每3天一次)
|
||
3. **剂量提醒**:提醒用户剩余药量不足
|
||
4. **服药历史**:长期服药历史分析和可视化
|
||
5. **多设备同步**:支持多设备间的数据同步
|
||
6. **家庭账户**:支持为家人管理用药
|
||
|
||
## 相关文档
|
||
|
||
- [API 规范文档](../../docs/medication-api-spec.md)
|
||
- [数据库设计](../../sql-scripts/medications-tables-create.sql)
|
||
- [推送通知文档](../push-notifications/README_PUSH_TEST.md)
|