27 KiB
27 KiB
系统架构设计文档
1. 系统概述
家庭药品与应急物资管理系统(YaoXiang)是一个基于 Web 的家庭药品库存管理系统,支持 AI 自动录入、智能搜索、到期提醒等功能。系统采用前后端分离架构,支持 Docker 单容器部署。
2. 技术栈
前端
- 框架: React 18+
- 语言: TypeScript
- 构建工具: Vite
- UI 库: Ant Design Mobile 5.x(移动端优化)
- 状态管理: Zustand
- 路由: React Router 6
- HTTP 客户端: Axios
- PWA: vite-plugin-pwa
后端
- 框架: FastAPI
- 语言: Python 3.11+
- ORM: SQLAlchemy 2.0
- 数据库迁移: Alembic
- 文件存储: 本地文件系统
- 任务队列: 无(采用异步任务)
数据库
- 主数据库: SQLite(可升级 PostgreSQL)
- 缓存: 无(可选 Redis)
AI Provider
- 多模态模型: OpenAI GPT-4o / Gemini / Claude
- 文本模型: DeepSeek / Ollama
- 抽象层: 统一 Provider 接口
部署
- 容器化: Docker
- 编排: Docker Compose
- 反向代理: Nginx(前端静态文件)
3. 系统架构图
┌─────────────────────────────────────────────────────────────┐
│ 客户端层 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 手机浏览器 │ │ 平板浏览器 │ │ PC 浏览器 │ │
│ │ (PWA) │ │ (大屏模式) │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 前端应用层 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ React App │ │ PWA 配置 │ │ 状态管理 │ │
│ │ (Vite) │ │ Service Worker │ │ (Zustand) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 页面组件 │ │ 业务组件 │ │ API 调用层 │ │
│ │ (Router) │ │ (Ant Design)│ │ (Axios) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ API 通信层 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │ RESTful API │ │
│ │ POST /api/auth/login │ │
│ │ GET /api/medicines │ │
│ │ POST /api/medicines │ │
│ │ POST /api/medicines/recognize │ │
│ │ ... │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 后端应用层 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ FastAPI │ │ 路由层 │ │ 中间件 │ │
│ │ (Router) │ │ (APIRouter)│ │ (Auth) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 服务层 │ │ 数据访问层 │ │ 模型层 │ │
│ │ (Service) │ │ (Repository)│ │ (Model) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ AI Provider│ │ 通知系统 │ │ 文件存储 │ │
│ │ (Abstract) │ │ (Provider) │ │ (Local) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 数据存储层 │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ SQLite │ │ 文件系统 │ │ 缓存 │ │
│ │ (Database) │ │ (Uploads) │ │ (可选) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
4. 模块划分
4.1 前端模块
frontend/
├── src/
│ ├── api/ # API 调用层
│ │ ├── client.ts # Axios 实例配置
│ │ ├── auth.ts # 认证相关 API
│ │ ├── medicines.ts # 药品管理 API
│ │ ├── categories.ts # 分类管理 API
│ │ ├── batches.ts # 批次管理 API
│ │ └── notifications.ts # 通知相关 API
│ ├── components/ # 业务组件
│ │ ├── MedicineCard/ # 药品卡片
│ │ ├── BatchForm/ # 批次表单
│ │ ├── CategoryTree/ # 分类树
│ │ └── SearchBar/ # 搜索栏
│ ├── pages/ # 页面组件
│ │ ├── Home/ # 首页(库存概览)
│ │ ├── MedicineList/ # 药品列表
│ │ ├── MedicineDetail/ # 药品详情
│ │ ├── AddMedicine/ # 添加药品
│ │ ├── QuickDispense/ # 快速取药(大屏模式)
│ │ ├── Scanner/ # AI 识别
│ │ ├── Search/ # 搜索页面
│ │ ├── Notifications/ # 通知中心
│ │ ├── Settings/ # 设置页面
│ │ └── Login/ # 登录页面
│ ├── stores/ # 状态管理
│ │ ├── authStore.ts # 认证状态
│ │ ├── medicineStore.ts # 药品状态
│ │ └── uiStore.ts # UI 状态
│ ├── hooks/ # 自定义 Hooks
│ │ ├── useAuth.ts # 认证 Hook
│ │ ├── useMedicine.ts # 药品 Hook
│ │ └── useCamera.ts # 摄像头 Hook
│ ├── utils/ # 工具函数
│ │ ├── date.ts # 日期处理
│ │ ├── storage.ts # 本地存储
│ │ └── validators.ts # 表单验证
│ ├── types/ # TypeScript 类型
│ │ ├── medicine.ts # 药品类型
│ │ ├── batch.ts # 批次类型
│ │ ├── user.ts # 用户类型
│ │ └── api.ts # API 响应类型
│ ├── styles/ # 样式文件
│ │ ├── global.css # 全局样式
│ │ └── variables.css # CSS 变量
│ ├── App.tsx # 根组件
│ ├── main.tsx # 入口文件
│ └── router.tsx # 路由配置
├── public/ # 静态资源
├── index.html # HTML 模板
├── vite.config.ts # Vite 配置
├── tsconfig.json # TypeScript 配置
└── package.json # 依赖配置
4.2 后端模块
backend/
├── app/
│ ├── api/ # 路由层
│ │ ├── v1/ # API 版本
│ │ │ ├── auth.py # 认证路由
│ │ │ ├── medicines.py # 药品路由
│ │ │ ├── batches.py # 批次路由
│ │ │ ├── categories.py # 分类路由
│ │ │ ├── search.py # 搜索路由
│ │ │ ├── notifications.py # 通知路由
│ │ │ ├── ai.py # AI 识别路由
│ │ │ └── users.py # 用户管理路由
│ │ └── router.py # 路由汇总
│ ├── core/ # 核心配置
│ │ ├── config.py # 配置管理
│ │ ├── security.py # 安全工具
│ │ └── deps.py # 依赖注入
│ ├── models/ # 数据模型
│ │ ├── medicine.py # 药品模型
│ │ ├── batch.py # 批次模型
│ │ ├── category.py # 分类模型
│ │ ├── user.py # 用户模型
│ │ ├── notification.py # 通知模型
│ │ └── audit.py # 审计日志模型
│ ├── schemas/ # Pydantic 模型
│ │ ├── medicine.py # 药品 Schema
│ │ ├── batch.py # 批次 Schema
│ │ ├── category.py # 分类 Schema
│ │ ├── user.py # 用户 Schema
│ │ └── auth.py # 认证 Schema
│ ├── services/ # 服务层
│ │ ├── medicine.py # 药品服务
│ │ ├── batch.py # 批次服务
│ │ ├── category.py # 分类服务
│ │ ├── user.py # 用户服务
│ │ ├── auth.py # 认证服务
│ │ ├── notification.py # 通知服务
│ │ └── search.py # 搜索服务
│ ├── repositories/ # 数据访问层
│ │ ├── medicine.py # 药品仓库
│ │ ├── batch.py # 批次仓库
│ │ ├── category.py # 分类仓库
│ │ └── user.py # 用户仓库
│ ├── ai/ # AI Provider
│ │ ├── provider.py # 抽象基类
│ │ ├── openai.py # OpenAI 实现
│ │ ├── gemini.py # Gemini 实现
│ │ ├── claude.py # Claude 实现
│ │ ├── deepseek.py # DeepSeek 实现
│ │ ├── ollama.py # Ollama 实现
│ │ └── manager.py # Provider 管理器
│ ├── notifications/ # 通知系统
│ │ ├── provider.py # 抽象基类
│ │ ├── serverchan.py # Server酱
│ │ ├── pushplus.py # PushPlus
│ │ ├── bark.py # Bark
│ │ ├── wechat.py # 企业微信
│ │ ├── telegram.py # Telegram
│ │ ├── email.py # 邮件
│ │ └── manager.py # 通知管理器
│ ├── storage/ # 文件存储
│ │ ├── local.py # 本地存储
│ │ └── manager.py # 存储管理器
│ ├── tasks/ # 异步任务
│ │ ├── expiry_check.py # 到期检查任务
│ │ └── stock_check.py # 库存检查任务
│ ├── database.py # 数据库连接
│ └── main.py # 应用入口
├── alembic/ # 数据库迁移
│ ├── versions/
│ └── env.py
├── tests/ # 测试文件
├── requirements.txt # 依赖配置
├── alembic.ini # Alembic 配置
├── Dockerfile # Docker 配置
└── .env.example # 环境变量示例
5. 数据流设计
5.1 AI 自动录入流程
用户上传图片
│
▼
┌─────────────────┐
│ 图片预处理 │
│ (压缩/格式化) │
└─────────────────┘
│
▼
┌─────────────────┐
│ 调用 Vision │
│ Provider │
└─────────────────┘
│
▼
┌─────────────────┐
│ 返回识别结果 │
│ (JSON) │
└─────────────────┘
│
▼
┌─────────────────┐
│ 用户确认/编辑 │
└─────────────────┘
│
▼
┌─────────────────┐
│ 保存到数据库 │
│ + 保存图片 │
└─────────────────┘
5.2 快速取药流程
用户选择药品
│
▼
┌─────────────────┐
│ 显示药品详情 │
│ (可用批次列表) │
└─────────────────┘
│
▼
┌─────────────────┐
│ 用户选择批次 │
│ 输入取药数量 │
└─────────────────┘
│
▼
┌─────────────────┐
│ 扣减库存 │
│ 记录审计日志 │
└─────────────────┘
│
▼
┌─────────────────┐
│ 检查库存阈值 │
│ 触发通知(可选) │
└─────────────────┘
5.3 到期提醒流程
定时任务触发
│
▼
┌─────────────────┐
│ 查询即将过期 │
│ 批次 (90/30/7天)│
└─────────────────┘
│
▼
┌─────────────────┐
│ 生成提醒内容 │
└─────────────────┘
│
▼
┌─────────────────┐
│ 调用通知系统 │
│ 发送提醒 │
└─────────────────┘
6. AI Provider 抽象层设计
6.1 抽象接口
from abc import ABC, abstractmethod
from typing import Optional
from pydantic import BaseModel
class VisionResult(BaseModel):
"""视觉识别结果"""
generic_name: str
brand_name: Optional[str]
manufacturer: Optional[str]
specification: Optional[str]
class DateResult(BaseModel):
"""日期识别结果"""
production_date: Optional[str]
expiry_date: Optional[str]
class LeafletResult(BaseModel):
"""说明书识别结果"""
indications: str
adult_dose: str
child_dose: Optional[str]
contraindications: str
notes: Optional[str]
class VisionProvider(ABC):
"""视觉模型提供者抽象基类"""
@abstractmethod
async def recognize_medicine(self, image_bytes: bytes) -> VisionResult:
"""识别药盒信息"""
pass
@abstractmethod
async def recognize_dates(self, image_bytes: bytes) -> DateResult:
"""识别日期信息"""
pass
class TextProvider(ABC):
"""文本模型提供者抽象基类"""
@abstractmethod
async def summarize_leaflet(self, text: str) -> LeafletResult:
"""总结说明书内容"""
pass
@abstractmethod
async def natural_language_search(self, query: str, medicines: list) -> list:
"""自然语言搜索"""
pass
6.2 Provider 管理器
class AIManager:
"""AI Provider 管理器"""
def __init__(self):
self.vision_providers: dict[str, VisionProvider] = {}
self.text_providers: dict[str, TextProvider] = {}
def register_vision_provider(self, name: str, provider: VisionProvider):
"""注册视觉模型提供者"""
self.vision_providers[name] = provider
def register_text_provider(self, name: str, provider: TextProvider):
"""注册文本模型提供者"""
self.text_providers[name] = provider
def get_vision_provider(self, name: str) -> VisionProvider:
"""获取视觉模型提供者"""
return self.vision_providers.get(name)
def get_text_provider(self, name: str) -> TextProvider:
"""获取文本模型提供者"""
return self.text_providers.get(name)
7. 通知系统设计
7.1 通知 Provider 抽象
from abc import ABC, abstractmethod
class NotificationProvider(ABC):
"""通知提供者抽象基类"""
@abstractmethod
async def send(self, title: str, content: str) -> bool:
"""发送通知"""
pass
@abstractmethod
def validate_config(self) -> bool:
"""验证配置"""
pass
7.2 通知管理器
class NotificationManager:
"""通知管理器"""
def __init__(self):
self.providers: list[NotificationProvider] = []
def add_provider(self, provider: NotificationProvider):
"""添加通知提供者"""
self.providers.append(provider)
async def send_notification(self, title: str, content: str):
"""发送通知到所有提供者"""
for provider in self.providers:
try:
await provider.send(title, content)
except Exception as e:
# 记录错误但不中断
pass
8. 认证授权设计
8.1 用户角色
- admin: 管理员,拥有所有权限
- user: 普通用户,可查看、添加库存、取药
- readonly: 只读用户,仅可查看
8.2 权限矩阵
| 功能 | admin | user | readonly |
|---|---|---|---|
| 查看药品 | ✓ | ✓ | ✓ |
| 添加药品 | ✓ | ✓ | ✗ |
| 修改药品 | ✓ | ✓ | ✗ |
| 删除药品 | ✓ | ✗ | ✗ |
| 取药 | ✓ | ✓ | ✗ |
| 用户管理 | ✓ | ✗ | ✗ |
| 系统设置 | ✓ | ✗ | ✗ |
| 通知管理 | ✓ | ✓ | ✗ |
8.3 JWT 认证流程
用户登录
│
▼
┌─────────────────┐
│ 验证用户名密码 │
└─────────────────┘
│
▼
┌─────────────────┐
│ 生成 JWT Token │
│ (Access Token) │
└─────────────────┘
│
▼
┌─────────────────┐
│ 返回 Token │
└─────────────────┘
│
▼
┌─────────────────┐
│ 前端存储 Token │
│ (localStorage) │
└─────────────────┘
│
▼
┌─────────────────┐
│ 后续请求携带 │
│ Authorization │
│ Header │
└─────────────────┘
9. 插件系统设计
9.1 插件接口
from abc import ABC, abstractmethod
class Plugin(ABC):
"""插件抽象基类"""
@abstractmethod
def get_name(self) -> str:
"""获取插件名称"""
pass
@abstractmethod
def get_description(self) -> str:
"""获取插件描述"""
pass
@abstractmethod
def initialize(self, app):
"""初始化插件"""
pass
9.2 插件管理器
class PluginManager:
"""插件管理器"""
def __init__(self):
self.plugins: dict[str, Plugin] = {}
def register_plugin(self, plugin: Plugin):
"""注册插件"""
name = plugin.get_name()
self.plugins[name] = plugin
def get_plugin(self, name: str) -> Plugin:
"""获取插件"""
return self.plugins.get(name)
def list_plugins(self) -> list[str]:
"""列出所有插件"""
return list(self.plugins.keys())
10. MCP 协议支持
10.1 MCP 工具定义
from mcp import Tool
# 查询库存工具
query_inventory_tool = Tool(
name="query_inventory",
description="查询家庭药品库存",
inputSchema={
"type": "object",
"properties": {
"medicine_name": {
"type": "string",
"description": "药品名称"
}
}
}
)
# 取药工具
dispense_medicine_tool = Tool(
name="dispense_medicine",
description="取药操作",
inputSchema={
"type": "object",
"properties": {
"medicine_id": {
"type": "integer",
"description": "药品ID"
},
"quantity": {
"type": "integer",
"description": "取药数量"
}
},
"required": ["medicine_id", "quantity"]
}
)
11. 部署架构
┌─────────────────────────────────────────┐
│ Docker 容器 │
├─────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Nginx │ │ FastAPI │ │
│ │ (静态文件) │ │ (后端) │ │
│ │ :80 │ │ :8000 │ │
│ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ SQLite │ │ 文件存储 │ │
│ │ (数据库) │ │ (图片) │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────┘
12. 环境变量配置
# 数据库配置
DATABASE_URL=sqlite:///./data/yaoxiang.db
# AI Provider 配置
AI_PROVIDER=openai
OPENAI_API_KEY=sk-xxx
OPENAI_MODEL=gpt-4o
# 通知配置
NOTIFICATION_PROVIDERS=serverchan,pushplus
SERVERCHAN_KEY=xxx
PUSHPLUS_TOKEN=xxx
# 安全配置
JWT_SECRET_KEY=xxx
JWT_ALGORITHM=HS256
JWT_EXPIRATION_HOURS=24
# 文件存储配置
UPLOAD_DIR=./data/uploads
MAX_UPLOAD_SIZE=10485760 # 10MB
# 应用配置
APP_NAME=药箱
APP_VERSION=1.0.0
DEBUG=false
13. 开发规范
13.1 代码风格
- Python: 遵循 PEP 8,使用 Black 格式化
- TypeScript: 遵循 ESLint 规则,使用 Prettier 格式化
- Git: 使用 Conventional Commits 规范
13.2 分支管理
main: 生产分支develop: 开发分支feature/*: 功能分支bugfix/*: 修复分支release/*: 发布分支
13.3 提交规范
feat: 新功能
fix: 修复 bug
docs: 文档更新
style: 代码格式调整
refactor: 重构
test: 测试相关
chore: 构建/工具相关
14. 性能优化
14.1 前端优化
- 路由懒加载
- 图片懒加载
- 虚拟列表(长列表优化)
- Service Worker 缓存
14.2 后端优化
- 数据库连接池
- 查询优化(索引、分页)
- 异步处理耗时任务
- 响应缓存
15. 安全设计
15.1 认证安全
- 密码使用 bcrypt 加密存储
- JWT Token 定期轮换
- 登录失败次数限制
15.2 数据安全
- 敏感配置使用环境变量
- 文件上传类型验证
- SQL 注入防护(ORM)
- XSS 防护(前端)
15.3 传输安全
- 支持 HTTPS
- CORS 配置
- 请求限流