541 lines
15 KiB
Markdown
541 lines
15 KiB
Markdown
# 药箱后端开发文档
|
||
|
||
## 1. 项目概述
|
||
|
||
药箱(YaoXiang)是一个家庭药品与应急物资管理系统,后端采用 FastAPI 框架,提供 RESTful API 服务。
|
||
|
||
## 2. 技术栈
|
||
|
||
| 技术 | 版本 | 说明 |
|
||
|------|------|------|
|
||
| Python | 3.11+ | 运行环境 |
|
||
| FastAPI | 0.104.1 | Web 框架 |
|
||
| SQLAlchemy | 2.0.23 | ORM 框架 |
|
||
| Alembic | 1.13.0 | 数据库迁移 |
|
||
| SQLite | - | 数据库 |
|
||
| Pydantic | 2.5.2 | 数据验证 |
|
||
| python-jose | 3.3.0 | JWT 认证 |
|
||
| passlib | 1.7.4 | 密码加密 |
|
||
| OpenAI | 1.6.1 | AI 服务 |
|
||
|
||
## 3. 项目结构
|
||
|
||
```
|
||
backend/
|
||
├── app/ # 主应用目录
|
||
│ ├── __init__.py
|
||
│ ├── main.py # FastAPI 应用入口
|
||
│ ├── config.py # 配置管理
|
||
│ ├── database.py # 数据库连接
|
||
│ │
|
||
│ ├── api/ # API 路由层
|
||
│ │ ├── router.py # 路由汇总
|
||
│ │ └── v1/ # API 版本 1
|
||
│ │ ├── auth.py # 认证接口
|
||
│ │ ├── medicines.py # 药品管理接口
|
||
│ │ ├── batches.py # 批次管理接口
|
||
│ │ ├── categories.py # 分类管理接口
|
||
│ │ ├── search.py # 搜索接口
|
||
│ │ ├── notifications.py # 通知接口
|
||
│ │ ├── ai.py # AI 识别接口
|
||
│ │ ├── users.py # 用户管理接口
|
||
│ │ └── settings.py # 系统设置接口
|
||
│ │
|
||
│ ├── models/ # SQLAlchemy 数据模型
|
||
│ │ ├── user.py # 用户模型
|
||
│ │ ├── medicine.py # 药品模型
|
||
│ │ ├── batch.py # 批次模型
|
||
│ │ ├── category.py # 分类模型
|
||
│ │ ├── audit_log.py # 审计日志模型
|
||
│ │ ├── notification.py # 通知模型
|
||
│ │ └── setting.py # 设置模型
|
||
│ │
|
||
│ ├── schemas/ # Pydantic 数据模式
|
||
│ │ ├── user.py
|
||
│ │ ├── medicine.py
|
||
│ │ ├── batch.py
|
||
│ │ ├── category.py
|
||
│ │ └── auth.py
|
||
│ │
|
||
│ ├── services/ # 业务服务层
|
||
│ │ ├── auth.py # 认证服务
|
||
│ │ ├── user.py # 用户服务
|
||
│ │ ├── medicine.py # 药品服务
|
||
│ │ ├── batch.py # 批次服务
|
||
│ │ ├── category.py # 分类服务
|
||
│ │ ├── audit.py # 审计日志服务
|
||
│ │ └── notification.py # 通知服务
|
||
│ │
|
||
│ ├── repositories/ # 数据访问层
|
||
│ │ ├── user.py
|
||
│ │ ├── medicine.py
|
||
│ │ ├── batch.py
|
||
│ │ ├── category.py
|
||
│ │ ├── audit_log.py
|
||
│ │ └── notification.py
|
||
│ │
|
||
│ ├── ai/ # AI Provider 模块
|
||
│ │ ├── base.py # 抽象基类
|
||
│ │ ├── openai_provider.py # OpenAI 实现
|
||
│ │ └── manager.py # Provider 管理器
|
||
│ │
|
||
│ ├── notifications/ # 通知系统
|
||
│ │ ├── base.py # 抽象基类
|
||
│ │ ├── serverchan.py # Server酱
|
||
│ │ ├── pushplus.py # PushPlus
|
||
│ │ └── manager.py # 通知管理器
|
||
│ │
|
||
│ ├── storage/ # 文件存储
|
||
│ │ ├── base.py # 抽象基类
|
||
│ │ ├── local.py # 本地存储
|
||
│ │ └── manager.py # 存储管理器
|
||
│ │
|
||
│ ├── core/ # 核心功能
|
||
│ │ ├── security.py # 安全工具 (JWT, 密码)
|
||
│ │ ├── deps.py # 依赖注入
|
||
│ │ └── exceptions.py # 异常处理
|
||
│ │
|
||
│ └── tasks/ # 异步任务
|
||
│ └── expiry_check.py # 到期检查任务
|
||
│
|
||
├── tests/ # 测试目录
|
||
├── data/ # 数据目录
|
||
├── requirements.txt # Python 依赖
|
||
├── .env.example # 环境变量示例
|
||
└── .env # 环境变量配置
|
||
```
|
||
|
||
## 4. 快速开始
|
||
|
||
### 4.1 环境准备
|
||
|
||
```bash
|
||
# 进入后端目录
|
||
cd backend
|
||
|
||
# 创建虚拟环境 (可选)
|
||
python -m venv venv
|
||
venv\Scripts\activate # Windows
|
||
# source venv/bin/activate # Linux/Mac
|
||
|
||
# 安装依赖
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
### 4.2 配置环境变量
|
||
|
||
```bash
|
||
# 复制环境变量示例文件
|
||
cp .env.example .env
|
||
|
||
# 编辑 .env 文件,配置必要的参数
|
||
```
|
||
|
||
### 4.3 启动服务
|
||
|
||
```bash
|
||
# 开发模式启动
|
||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||
|
||
# 生产模式启动
|
||
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
|
||
```
|
||
|
||
### 4.4 访问 API 文档
|
||
|
||
- Swagger UI: http://localhost:8000/docs
|
||
- ReDoc: http://localhost:8000/redoc
|
||
- 健康检查: http://localhost:8000/health
|
||
|
||
## 5. 配置说明
|
||
|
||
### 5.1 环境变量配置
|
||
|
||
| 变量名 | 默认值 | 说明 |
|
||
|--------|--------|------|
|
||
| DATABASE_URL | sqlite+aiosqlite:///./data/yaoxiang.db | 数据库连接字符串 |
|
||
| JWT_SECRET_KEY | your-secret-key-change-in-production | JWT 密钥 |
|
||
| JWT_ALGORITHM | HS256 | JWT 算法 |
|
||
| JWT_EXPIRATION_HOURS | 24 | JWT 过期时间(小时) |
|
||
| AI_PROVIDER | openai | AI 服务提供者 |
|
||
| OPENAI_API_KEY | - | OpenAI API Key |
|
||
| OPENAI_MODEL | gpt-4o | OpenAI 模型 |
|
||
| UPLOAD_DIR | ./data/uploads | 文件上传目录 |
|
||
| CORS_ORIGINS | http://localhost:5173 | CORS 允许的源 |
|
||
|
||
### 5.2 AI Provider 配置
|
||
|
||
支持的 AI Provider:
|
||
- **openai**: OpenAI GPT-4o
|
||
- **gemini**: Google Gemini
|
||
- **claude**: Anthropic Claude
|
||
- **deepseek**: DeepSeek
|
||
- **ollama**: 本地 Ollama
|
||
|
||
## 6. 数据库设计
|
||
|
||
### 6.1 数据表
|
||
|
||
| 表名 | 说明 |
|
||
|------|------|
|
||
| users | 用户表 |
|
||
| categories | 分类表 |
|
||
| medicines | 药品表 |
|
||
| batches | 批次表 |
|
||
| audit_logs | 审计日志表 |
|
||
| notifications | 通知表 |
|
||
| settings | 系统设置表 |
|
||
|
||
### 6.2 核心表结构
|
||
|
||
#### users 表
|
||
```sql
|
||
CREATE TABLE users (
|
||
id INTEGER PRIMARY KEY,
|
||
username VARCHAR(50) UNIQUE NOT NULL,
|
||
password_hash VARCHAR(255) NOT NULL,
|
||
role VARCHAR(20) DEFAULT 'user',
|
||
display_name VARCHAR(100),
|
||
email VARCHAR(100),
|
||
notification_level VARCHAR(20) DEFAULT 'normal',
|
||
is_active BOOLEAN DEFAULT TRUE,
|
||
created_at TIMESTAMP,
|
||
updated_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
#### medicines 表
|
||
```sql
|
||
CREATE TABLE medicines (
|
||
id INTEGER PRIMARY KEY,
|
||
name VARCHAR(200) NOT NULL,
|
||
generic_name VARCHAR(200),
|
||
brand_name VARCHAR(200),
|
||
manufacturer VARCHAR(200),
|
||
specification VARCHAR(200),
|
||
category_id INTEGER REFERENCES categories(id),
|
||
indications TEXT,
|
||
adult_dose TEXT,
|
||
child_dose TEXT,
|
||
contraindications TEXT,
|
||
notes TEXT,
|
||
image_front_path VARCHAR(500),
|
||
image_expiry_path VARCHAR(500),
|
||
image_leaflet_paths JSON,
|
||
expiry_grace_days INTEGER DEFAULT 0,
|
||
created_by INTEGER REFERENCES users(id),
|
||
created_at TIMESTAMP,
|
||
updated_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
#### batches 表
|
||
```sql
|
||
CREATE TABLE batches (
|
||
id INTEGER PRIMARY KEY,
|
||
medicine_id INTEGER REFERENCES medicines(id),
|
||
batch_no VARCHAR(100),
|
||
production_date DATE,
|
||
expiry_date DATE NOT NULL,
|
||
quantity INTEGER DEFAULT 0,
|
||
location VARCHAR(200),
|
||
is_expired BOOLEAN DEFAULT FALSE,
|
||
created_at TIMESTAMP,
|
||
updated_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
## 7. API 接口
|
||
|
||
### 7.1 认证接口
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| POST | /api/v1/auth/login | 用户登录 |
|
||
| GET | /api/v1/auth/me | 获取当前用户信息 |
|
||
| PUT | /api/v1/auth/password | 修改密码 |
|
||
|
||
### 7.2 药品管理接口
|
||
|
||
| 方法 | 路径 | 说明 | 权限 |
|
||
|------|------|------|------|
|
||
| GET | /api/v1/medicines | 获取药品列表 | 登录用户 |
|
||
| GET | /api/v1/medicines/{id} | 获取药品详情 | 登录用户 |
|
||
| POST | /api/v1/medicines | 创建药品 | admin/user |
|
||
| PUT | /api/v1/medicines/{id} | 更新药品 | admin/user |
|
||
| DELETE | /api/v1/medicines/{id} | 删除药品 | admin |
|
||
|
||
### 7.3 批次管理接口
|
||
|
||
| 方法 | 路径 | 说明 | 权限 |
|
||
|------|------|------|------|
|
||
| GET | /api/v1/batches/medicine/{medicine_id} | 获取药品的所有批次 | 登录用户 |
|
||
| GET | /api/v1/batches/{id} | 获取批次详情 | 登录用户 |
|
||
| POST | /api/v1/batches/medicine/{medicine_id} | 创建批次 | admin/user |
|
||
| PUT | /api/v1/batches/{id} | 更新批次 | admin/user |
|
||
| DELETE | /api/v1/batches/{id} | 删除批次 | admin |
|
||
| POST | /api/v1/batches/{id}/dispense | 取药 | admin/user |
|
||
| POST | /api/v1/batches/{id}/add-stock | 入库 | admin/user |
|
||
|
||
### 7.4 分类管理接口
|
||
|
||
| 方法 | 路径 | 说明 | 权限 |
|
||
|------|------|------|------|
|
||
| GET | /api/v1/categories | 获取分类列表 | 登录用户 |
|
||
| GET | /api/v1/categories/tree | 获取分类树 | 登录用户 |
|
||
| GET | /api/v1/categories/{id} | 获取分类详情 | 登录用户 |
|
||
| POST | /api/v1/categories | 创建分类 | admin |
|
||
| PUT | /api/v1/categories/{id} | 更新分类 | admin |
|
||
| DELETE | /api/v1/categories/{id} | 删除分类 | admin |
|
||
|
||
### 7.5 搜索接口
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | /api/v1/search?q=关键词 | 关键词搜索 |
|
||
| POST | /api/v1/search/natural | 自然语言搜索 |
|
||
|
||
### 7.6 AI 识别接口
|
||
|
||
| 方法 | 路径 | 说明 | 权限 |
|
||
|------|------|------|------|
|
||
| POST | /api/v1/ai/recognize-medicine | 识别药盒 | admin/user |
|
||
| POST | /api/v1/ai/recognize-dates | 识别日期 | admin/user |
|
||
| POST | /api/v1/ai/recognize-leaflet | 识别说明书 | admin/user |
|
||
|
||
### 7.7 用户管理接口
|
||
|
||
| 方法 | 路径 | 说明 | 权限 |
|
||
|------|------|------|------|
|
||
| GET | /api/v1/users | 获取用户列表 | admin |
|
||
| GET | /api/v1/users/{id} | 获取用户详情 | admin |
|
||
| POST | /api/v1/users | 创建用户 | admin |
|
||
| PUT | /api/v1/users/{id} | 更新用户 | admin |
|
||
| DELETE | /api/v1/users/{id} | 删除用户 | admin |
|
||
| POST | /api/v1/users/{id}/reset-password | 重置密码 | admin |
|
||
|
||
### 7.8 通知接口
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | /api/v1/notifications | 获取通知列表 |
|
||
| PUT | /api/v1/notifications/{id}/read | 标记为已读 |
|
||
| PUT | /api/v1/notifications/read-all | 全部标记为已读 |
|
||
| DELETE | /api/v1/notifications/{id} | 删除通知 |
|
||
|
||
### 7.9 系统设置接口
|
||
|
||
| 方法 | 路径 | 说明 | 权限 |
|
||
|------|------|------|------|
|
||
| GET | /api/v1/settings | 获取所有设置 | admin |
|
||
| GET | /api/v1/settings/{key} | 获取单个设置 | admin |
|
||
| PUT | /api/v1/settings/{key} | 更新设置 | admin |
|
||
|
||
## 8. 开发指南
|
||
|
||
### 8.1 添加新的 API 接口
|
||
|
||
1. 在 `app/api/v1/` 目录下创建或修改路由文件
|
||
2. 定义请求和响应的 Pydantic 模式
|
||
3. 实现业务逻辑(服务层)
|
||
4. 在 `app/api/router.py` 中注册路由
|
||
|
||
示例:
|
||
```python
|
||
# app/api/v1/example.py
|
||
from fastapi import APIRouter, Depends
|
||
from app.core.deps import get_current_user
|
||
|
||
router = APIRouter()
|
||
|
||
@router.get("/")
|
||
async def list_examples(current_user = Depends(get_current_user)):
|
||
return {"message": "success"}
|
||
```
|
||
|
||
### 8.2 添加新的数据模型
|
||
|
||
1. 在 `app/models/` 目录下创建模型文件
|
||
2. 继承 `Base` 类
|
||
3. 定义表名和字段
|
||
4. 在 `app/models/__init__.py` 中导入
|
||
|
||
```python
|
||
# app/models/example.py
|
||
from sqlalchemy import Column, Integer, String
|
||
from app.database import Base
|
||
|
||
class Example(Base):
|
||
__tablename__ = "examples"
|
||
|
||
id = Column(Integer, primary_key=True, index=True)
|
||
name = Column(String(100), nullable=False)
|
||
```
|
||
|
||
### 8.3 添加新的服务
|
||
|
||
1. 在 `app/services/` 目录下创建服务文件
|
||
2. 实现业务逻辑
|
||
3. 使用 Repository 进行数据访问
|
||
|
||
```python
|
||
# app/services/example.py
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
from app.repositories.example import ExampleRepository
|
||
|
||
class ExampleService:
|
||
def __init__(self, db: AsyncSession):
|
||
self.db = db
|
||
self.repo = ExampleRepository(db)
|
||
|
||
async def get_example(self, example_id: int):
|
||
return await self.repo.get_by_id(example_id)
|
||
```
|
||
|
||
### 8.4 添加新的 AI Provider
|
||
|
||
1. 在 `app/ai/` 目录下创建 Provider 文件
|
||
2. 继承 `VisionProvider` 或 `TextProvider`
|
||
3. 实现抽象方法
|
||
4. 在 `app/ai/manager.py` 中注册
|
||
|
||
```python
|
||
# app/ai/custom_provider.py
|
||
from app.ai.base import VisionProvider, VisionResult
|
||
|
||
class CustomVisionProvider(VisionProvider):
|
||
async def recognize_medicine(self, image_bytes: bytes) -> VisionResult:
|
||
# 实现识别逻辑
|
||
return VisionResult(generic_name="药品名称")
|
||
|
||
async def recognize_dates(self, image_bytes: bytes):
|
||
# 实现日期识别
|
||
pass
|
||
```
|
||
|
||
### 8.5 添加新的通知 Provider
|
||
|
||
1. 在 `app/notifications/` 目录下创建 Provider 文件
|
||
2. 继承 `NotificationProvider`
|
||
3. 实现 `send` 和 `validate_config` 方法
|
||
|
||
```python
|
||
# app/notifications/custom.py
|
||
from app.notifications.base import NotificationProvider
|
||
|
||
class CustomNotificationProvider(NotificationProvider):
|
||
def __init__(self):
|
||
self.config = "your-config"
|
||
|
||
def validate_config(self) -> bool:
|
||
return bool(self.config)
|
||
|
||
async def send(self, title: str, content: str) -> bool:
|
||
# 实现发送逻辑
|
||
return True
|
||
```
|
||
|
||
## 9. 测试
|
||
|
||
### 9.1 运行测试
|
||
|
||
```bash
|
||
# 运行所有测试
|
||
pytest
|
||
|
||
# 运行特定测试
|
||
pytest tests/test_auth.py
|
||
|
||
# 运行带详细输出的测试
|
||
pytest -v
|
||
```
|
||
|
||
### 9.2 编写测试
|
||
|
||
```python
|
||
# tests/test_example.py
|
||
import pytest
|
||
from httpx import AsyncClient
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_health_check(client: AsyncClient):
|
||
response = await client.get("/health")
|
||
assert response.status_code == 200
|
||
assert response.json()["status"] == "healthy"
|
||
```
|
||
|
||
## 10. 部署
|
||
|
||
### 10.1 Docker 部署
|
||
|
||
```dockerfile
|
||
# Dockerfile
|
||
FROM python:3.11-slim
|
||
|
||
WORKDIR /app
|
||
|
||
COPY requirements.txt .
|
||
RUN pip install --no-cache-dir -r requirements.txt
|
||
|
||
COPY . .
|
||
|
||
EXPOSE 8000
|
||
|
||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||
```
|
||
|
||
### 10.2 生产环境配置
|
||
|
||
```bash
|
||
# 设置环境变量
|
||
export DATABASE_URL=sqlite+aiosqlite:///./data/yaoxiang.db
|
||
export JWT_SECRET_KEY=your-production-secret-key
|
||
export DEBUG=false
|
||
|
||
# 启动服务
|
||
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
|
||
```
|
||
|
||
## 11. 常见问题
|
||
|
||
### 11.1 数据库初始化失败
|
||
|
||
检查 `data/` 目录是否存在,确保有写入权限。
|
||
|
||
### 11.2 AI 服务连接失败
|
||
|
||
检查 `.env` 文件中的 API Key 配置是否正确。
|
||
|
||
### 11.3 文件上传失败
|
||
|
||
检查 `UPLOAD_DIR` 配置的目录是否存在,确保有写入权限。
|
||
|
||
## 12. 扩展开发
|
||
|
||
### 12.1 添加新的通知渠道
|
||
|
||
参考 `app/notifications/serverchan.py` 实现新的通知 Provider。
|
||
|
||
### 12.2 添加新的 AI 能力
|
||
|
||
1. 扩展 `app/ai/base.py` 中的抽象基类
|
||
2. 实现新的 Provider
|
||
3. 在 `app/ai/manager.py` 中注册
|
||
|
||
### 12.3 添加新的定时任务
|
||
|
||
使用 APScheduler 添加定时任务:
|
||
|
||
```python
|
||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||
|
||
scheduler = AsyncIOScheduler()
|
||
|
||
async def my_task():
|
||
# 任务逻辑
|
||
pass
|
||
|
||
scheduler.add_job(my_task, 'cron', hour=9, minute=0)
|
||
scheduler.start()
|
||
```
|