Files
YaoXiang/backend/DEVELOPMENT.md
T
2026-06-15 14:50:15 +08:00

541 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 药箱后端开发文档
## 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()
```