13 KiB
13 KiB
药箱前端开发文档
1. 项目概述
药箱(YaoXiang)是一个家庭药品与应急物资管理系统,前端采用 React + TypeScript + Vite 技术栈,支持 PWA 和大屏模式。
2. 技术栈
| 技术 | 版本 | 说明 |
|---|---|---|
| React | 18.2.0 | UI 框架 |
| TypeScript | 5.2.2 | 类型系统 |
| Vite | 5.0.0 | 构建工具 |
| React Router | 6.20.0 | 路由管理 |
| Zustand | 4.4.7 | 状态管理 |
| Ant Design Mobile | 5.34.0 | UI 组件库 |
| Axios | 1.6.2 | HTTP 客户端 |
| Day.js | 1.11.10 | 日期处理 |
3. 项目结构
frontend/
├── public/ # 静态资源
│ ├── favicon.svg # 网站图标
│ ├── manifest.json # PWA 配置
│ └── icons/ # 应用图标
│
├── src/
│ ├── api/ # API 调用层
│ │ ├── client.ts # Axios 实例配置
│ │ ├── auth.ts # 认证相关 API
│ │ ├── medicines.ts # 药品管理 API
│ │ ├── batches.ts # 批次管理 API
│ │ ├── categories.ts # 分类管理 API
│ │ ├── search.ts # 搜索 API
│ │ ├── notifications.ts # 通知 API
│ │ ├── users.ts # 用户管理 API
│ │ └── index.ts # 导出汇总
│ │
│ ├── components/ # 公共组件
│ │ ├── Layout/ # 布局组件(含 TabBar)
│ │ ├── MedicineCard/ # 药品卡片
│ │ ├── QuantitySelector/ # 数量选择器
│ │ ├── SearchBar/ # 搜索栏
│ │ ├── CameraCapture/ # 摄像头捕获
│ │ ├── CategoryTree/ # 分类树
│ │ └── index.ts # 导出汇总
│ │
│ ├── pages/ # 页面组件
│ │ ├── Home/ # 首页(库存概览)
│ │ ├── Login/ # 登录页
│ │ ├── MedicineList/ # 药品列表
│ │ ├── MedicineDetail/ # 药品详情
│ │ ├── AddMedicine/ # 添加/编辑药品
│ │ ├── QuickDispense/ # 快速取药(大屏模式)
│ │ ├── Search/ # 搜索页
│ │ ├── Notifications/ # 通知中心
│ │ ├── Settings/ # 设置页
│ │ └── index.ts # 导出汇总
│ │
│ ├── stores/ # 状态管理
│ │ ├── authStore.ts # 认证状态
│ │ ├── medicineStore.ts # 药品状态
│ │ ├── categoryStore.ts # 分类状态
│ │ ├── notificationStore.ts # 通知状态
│ │ ├── uiStore.ts # UI 状态
│ │ └── index.ts # 导出汇总
│ │
│ ├── hooks/ # 自定义 Hooks
│ │ ├── useAuth.ts # 认证 Hook
│ │ ├── useMedicine.ts # 药品 Hook
│ │ ├── useCamera.ts # 摄像头 Hook
│ │ ├── useNotification.ts # 通知 Hook
│ │ └── index.ts # 导出汇总
│ │
│ ├── types/ # TypeScript 类型定义
│ │ ├── user.ts # 用户类型
│ │ ├── medicine.ts # 药品类型
│ │ ├── batch.ts # 批次类型
│ │ ├── category.ts # 分类类型
│ │ ├── notification.ts # 通知类型
│ │ ├── api.ts # API 响应类型
│ │ └── index.ts # 导出汇总
│ │
│ ├── utils/ # 工具函数
│ │ ├── date.ts # 日期处理
│ │ ├── storage.ts # 本地存储
│ │ ├── validators.ts # 表单验证
│ │ ├── constants.ts # 常量定义
│ │ └── index.ts # 导出汇总
│ │
│ ├── styles/ # 样式文件
│ │ ├── global.css # 全局样式
│ │ ├── variables.css # CSS 变量
│ │ ├── mixins.css # CSS 混入
│ │ └── index.css # 导入汇总
│ │
│ ├── App.tsx # 根组件
│ ├── main.tsx # 入口文件
│ └── router.tsx # 路由配置
│
├── index.html # HTML 模板
├── package.json # 依赖配置
├── vite.config.ts # Vite 配置
├── tsconfig.json # TypeScript 配置
├── tsconfig.node.json # Node TypeScript 配置
├── .env.example # 环境变量示例
└── .gitignore # Git 忽略文件
4. 快速开始
4.1 环境准备
# 进入前端目录
cd frontend
# 安装依赖
npm install
4.2 配置环境变量
# 复制环境变量示例文件
cp .env.example .env
# 编辑 .env 文件
VITE_API_BASE_URL=/api
4.3 启动开发服务器
npm run dev
4.4 构建生产版本
npm run build
构建产物位于 dist/ 目录。
4.5 预览生产版本
npm run preview
5. 路由配置
5.1 路由表
| 路径 | 页面 | 说明 | 权限 |
|---|---|---|---|
/login |
Login | 登录页 | 公开 |
/ |
Home | 首页 | 登录用户 |
/medicines |
MedicineList | 药品列表 | 登录用户 |
/medicines/add |
AddMedicine | 添加药品 | admin/user |
/medicines/:id |
MedicineDetail | 药品详情 | 登录用户 |
/medicines/edit/:id |
AddMedicine | 编辑药品 | admin/user |
/quick-dispense |
QuickDispense | 快速取药 | 登录用户 |
/search |
Search | 搜索页 | 登录用户 |
/notifications |
Notifications | 通知中心 | 登录用户 |
/settings |
Settings | 设置页 | 登录用户 |
5.2 路由守卫
路由守卫通过 useAuth Hook 实现:
import { useAuth } from '../hooks';
const ProtectedRoute = ({ children }) => {
const { isAuthenticated } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return children;
};
6. 状态管理
6.1 Store 结构
| Store | 说明 | 主要状态 |
|---|---|---|
| authStore | 认证状态 | user, token, isAuthenticated |
| medicineStore | 药品状态 | medicines, currentMedicine, loading |
| categoryStore | 分类状态 | categories, loading |
| notificationStore | 通知状态 | notifications, unreadCount |
| uiStore | UI 状态 | isLargeScreen, isDarkMode |
6.2 使用示例
import { useMedicineStore } from '../stores';
const MyComponent = () => {
const { medicines, loading, fetchMedicines } = useMedicineStore();
useEffect(() => {
fetchMedicines();
}, []);
return (
<div>
{loading ? '加载中...' : medicines.map(m => <div key={m.id}>{m.name}</div>)}
</div>
);
};
7. API 调用
7.1 API 客户端配置
// api/client.ts
import axios from 'axios';
import { useAuthStore } from '../stores/authStore';
const client = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
timeout: 30000,
});
// 请求拦截器 - 添加 Token
client.interceptors.request.use((config) => {
const token = useAuthStore.getState().token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 响应拦截器 - 处理 401
client.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
useAuthStore.getState().logout();
window.location.href = '/login';
}
return Promise.reject(error);
}
);
7.2 API 调用示例
import { medicineApi } from '../api';
// 获取药品列表
const { data, total } = await medicineApi.list({ page: 1, pageSize: 20 });
// 创建药品
const medicine = await medicineApi.create({ name: '布洛芬', specification: '0.3g' });
// AI 识别药盒
const result = await medicineApi.recognize(imageFile);
8. 组件开发
8.1 添加新组件
- 在
src/components/目录下创建组件文件夹 - 创建
index.tsx和index.css - 在
src/components/index.ts中导出
// components/MyComponent/index.tsx
import React from 'react';
import './index.css';
interface MyComponentProps {
title: string;
}
const MyComponent: React.FC<MyComponentProps> = ({ title }) => {
return <div className="my-component">{title}</div>;
};
export default MyComponent;
8.2 添加新页面
- 在
src/pages/目录下创建页面文件夹 - 创建
index.tsx和index.css - 在
src/pages/index.ts中导出 - 在
src/router.tsx中添加路由
// pages/MyPage/index.tsx
import React from 'react';
import './index.css';
const MyPage: React.FC = () => {
return <div className="my-page">My Page</div>;
};
export default MyPage;
8.3 添加新 Hook
- 在
src/hooks/目录下创建 Hook 文件 - 在
src/hooks/index.ts中导出
// hooks/useMyHook.ts
import { useState, useCallback } from 'react';
export const useMyHook = () => {
const [data, setData] = useState(null);
const fetchData = useCallback(async () => {
// 实现逻辑
}, []);
return { data, fetchData };
};
9. 样式开发
9.1 CSS 变量
项目使用 CSS 变量管理主题:
:root {
--adm-color-primary: #1677ff;
--adm-color-success: #52c41a;
--adm-color-warning: #faad14;
--adm-color-danger: #ff4d4f;
}
9.2 大屏模式适配
/* 基础样式 */
.quantity-btn {
width: 48px;
height: 48px;
}
/* 大屏模式 */
@media (min-width: 768px) {
.quantity-btn {
width: 80px;
height: 80px;
}
}
9.3 使用 Ant Design Mobile 样式
import { Button } from 'antd-mobile';
// 使用组件自带样式
<Button color="primary" size="large">按钮</Button>
// 使用自定义样式
<div className="custom-wrapper">
<Button>按钮</Button>
</div>
10. 类型定义
10.1 添加新类型
- 在
src/types/目录下创建类型文件 - 在
src/types/index.ts中导出
// types/myType.ts
export interface MyType {
id: number;
name: string;
createdAt: string;
}
export interface MyTypeCreate {
name: string;
}
10.2 使用类型
import { MyType, MyTypeCreate } from '../types';
const myFunction = (data: MyTypeCreate): MyType => {
return { id: 1, ...data, createdAt: new Date().toISOString() };
};
11. 开发规范
11.1 代码风格
- 使用 TypeScript 严格模式
- 遵循 ESLint 规则
- 使用 Prettier 格式化
11.2 命名规范
| 类型 | 规范 | 示例 |
|---|---|---|
| 组件 | PascalCase | MedicineCard |
| Hook | use + PascalCase | useAuth |
| 函数 | camelCase | fetchMedicines |
| 变量 | camelCase | medicineList |
| 常量 | UPPER_SNAKE_CASE | API_BASE_URL |
| 文件 | PascalCase (组件) / camelCase (其他) | MedicineCard/index.tsx |
| CSS 类 | kebab-case | medicine-card |
11.3 文件组织
- 每个组件/页面单独一个文件夹
- 包含
index.tsx和index.css - 通过
index.ts导出
11.4 提交规范
feat: 新功能
fix: 修复 bug
docs: 文档更新
style: 代码格式调整
refactor: 重构
test: 测试相关
chore: 构建/工具相关
12. 构建与部署
12.1 开发环境
npm run dev
12.2 生产构建
npm run build
12.3 部署到 Nginx
server {
listen 80;
server_name your-domain.com;
root /path/to/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
13. 常见问题
13.1 开发服务器启动失败
检查端口是否被占用:
# Windows
netstat -ano | findstr :5173
# Mac/Linux
lsof -i :5173
13.2 API 请求失败
- 检查后端服务是否启动
- 检查
.env中的VITE_API_BASE_URL配置 - 检查浏览器控制台错误
13.3 类型错误
确保所有组件和函数都有正确的类型注解:
// 错误
const handleClick = (e) => { ... }
// 正确
const handleClick = (e: React.MouseEvent) => { ... }
13.4 样式不生效
- 检查 CSS 文件是否正确导入
- 检查选择器是否正确
- 使用浏览器开发者工具检查样式
14. 扩展开发
14.1 添加新的 AI 识别功能
- 在
src/api/medicines.ts中添加 API 调用 - 在页面中使用摄像头组件捕获图片
- 调用 AI 接口识别
14.2 添加新的通知渠道
- 在后端添加通知 Provider
- 在前端通知页面展示
14.3 添加新的页面
- 创建页面组件
- 添加路由配置
- 添加导航入口