首次提交by MimoCode
This commit is contained in:
@@ -0,0 +1,543 @@
|
||||
# 药箱前端开发文档
|
||||
|
||||
## 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. 添加导航入口
|
||||
Reference in New Issue
Block a user