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

544 lines
13 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)是一个家庭药品与应急物资管理系统,前端采用 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 环境准备
```bash
# 进入前端目录
cd frontend
# 安装依赖
npm install
```
### 4.2 配置环境变量
```bash
# 复制环境变量示例文件
cp .env.example .env
# 编辑 .env 文件
VITE_API_BASE_URL=/api
```
### 4.3 启动开发服务器
```bash
npm run dev
```
访问 http://localhost:5173
### 4.4 构建生产版本
```bash
npm run build
```
构建产物位于 `dist/` 目录。
### 4.5 预览生产版本
```bash
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 实现:
```tsx
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 使用示例
```tsx
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 客户端配置
```typescript
// 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 调用示例
```typescript
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 添加新组件
1.`src/components/` 目录下创建组件文件夹
2. 创建 `index.tsx``index.css`
3.`src/components/index.ts` 中导出
```tsx
// 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 添加新页面
1.`src/pages/` 目录下创建页面文件夹
2. 创建 `index.tsx``index.css`
3.`src/pages/index.ts` 中导出
4.`src/router.tsx` 中添加路由
```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
1.`src/hooks/` 目录下创建 Hook 文件
2.`src/hooks/index.ts` 中导出
```tsx
// 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 变量管理主题:
```css
:root {
--adm-color-primary: #1677ff;
--adm-color-success: #52c41a;
--adm-color-warning: #faad14;
--adm-color-danger: #ff4d4f;
}
```
### 9.2 大屏模式适配
```css
/* 基础样式 */
.quantity-btn {
width: 48px;
height: 48px;
}
/* 大屏模式 */
@media (min-width: 768px) {
.quantity-btn {
width: 80px;
height: 80px;
}
}
```
### 9.3 使用 Ant Design Mobile 样式
```tsx
import { Button } from 'antd-mobile';
// 使用组件自带样式
<Button color="primary" size="large">按钮</Button>
// 使用自定义样式
<div className="custom-wrapper">
<Button>按钮</Button>
</div>
```
## 10. 类型定义
### 10.1 添加新类型
1.`src/types/` 目录下创建类型文件
2.`src/types/index.ts` 中导出
```typescript
// types/myType.ts
export interface MyType {
id: number;
name: string;
createdAt: string;
}
export interface MyTypeCreate {
name: string;
}
```
### 10.2 使用类型
```typescript
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 开发环境
```bash
npm run dev
```
### 12.2 生产构建
```bash
npm run build
```
### 12.3 部署到 Nginx
```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 开发服务器启动失败
检查端口是否被占用:
```bash
# Windows
netstat -ano | findstr :5173
# Mac/Linux
lsof -i :5173
```
### 13.2 API 请求失败
1. 检查后端服务是否启动
2. 检查 `.env` 中的 `VITE_API_BASE_URL` 配置
3. 检查浏览器控制台错误
### 13.3 类型错误
确保所有组件和函数都有正确的类型注解:
```typescript
// 错误
const handleClick = (e) => { ... }
// 正确
const handleClick = (e: React.MouseEvent) => { ... }
```
### 13.4 样式不生效
1. 检查 CSS 文件是否正确导入
2. 检查选择器是否正确
3. 使用浏览器开发者工具检查样式
## 14. 扩展开发
### 14.1 添加新的 AI 识别功能
1.`src/api/medicines.ts` 中添加 API 调用
2. 在页面中使用摄像头组件捕获图片
3. 调用 AI 接口识别
### 14.2 添加新的通知渠道
1. 在后端添加通知 Provider
2. 在前端通知页面展示
### 14.3 添加新的页面
1. 创建页面组件
2. 添加路由配置
3. 添加导航入口