首次提交by MimoCode

This commit is contained in:
tang1219
2026-06-15 14:50:15 +08:00
parent 584b31da50
commit ead13f863c
166 changed files with 14908 additions and 1 deletions
+540
View File
@@ -0,0 +1,540 @@
# 药箱后端开发文档
## 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()
```