# BasicLayout.tsx 文档
## 文件职责
`BasicLayout` 是应用的根布局组件,负责:
1. **整体页面结构**:定义应用的主要布局框架(品牌区、状态栏、导航区、内容区)
2. **响应式适配**:根据不同屏幕尺寸提供不同的导航方式和布局
3. **页面路由管理**:通过业务流程状态切换不同的页面组件
4. **全局布局配置**:支持配置化的布局选项(如品牌区和状态栏位置)
## 实现方式
### 1. 技术栈
- **React**:组件化开发
- **Redux**:全局状态管理(业务流程状态)
- **Ant Design**:布局系统(Layout、Row、Col、ConfigProvider)
- **Ant Design Mobile**:移动端 TabBar
- **Tailwind CSS**:响应式样式和工具类
### 2. 核心组件结构
```
BasicLayout
├── ConfigProvider (Ant Design 主题配置)
└── Layout
├── Row (品牌和状态区域 - 可配置位置)
│ ├── Col (品牌区域)
│ └── Col (状态区域)
├── Row (主内容区域)
│ ├── Col (导航区域 - 仅大屏显示)
│ └── Col (内容区域)
├── Row (品牌和状态区域 - 底部位置)
├── TabBar (移动端底部导航 - 仅小屏显示)
└── NavbarFloat (中等屏幕浮动导航)
```
### 3. 响应式断点策略
| 屏幕尺寸 | 导航方式 | 品牌/状态栏 |
| ------------ | ---------------- | ----------- |
| xl (≥1200px) | 侧边 NavMenu | 显示 |
| lg (≥992px) | 侧边 NavMenu | 显示 |
| md (≥768px) | 浮动 NavbarFloat | 显示 |
| sm (≥576px) | 底部 TabBar | 隐藏 |
| xs (<576px) | 底部 TabBar | 隐藏 |
## 实现思路
### 1. 页面映射机制
使用 `contentMap` 对象建立业务流程 key 与页面组件的映射关系:
```typescript
const contentMap = {
exam: ,
process: ,
view: ,
register: ,
worklist: ,
// ... 其他页面
};
```
**优势**:
- 集中管理所有页面路由
- 易于添加新页面
- 避免复杂的条件判断
### 2. 状态驱动渲染
通过 Redux 的 `currentKey` 状态控制当前显示的页面:
```typescript
const currentKey = useSelector(
(state: RootState) => state.BusinessFlow.currentKey
);
// 渲染对应页面
{
contentMap[currentKey];
}
```
### 3. 配置化布局
从配置文件读取布局参数,支持动态调整:
```typescript
{pageLayoutConfig.brandAndStatusPosition === 'top' && (
品牌和状态区域
)}
```
### 4. 响应式导航策略
- **大屏(xl/lg)**:使用侧边栏 `NavMenu`
- **中屏(md)**:使用浮动菜单 `NavbarFloat`
- **小屏(sm/xs)**:使用底部 `TabBar`
通过 Tailwind CSS 的响应式工具类实现:
```typescript
className = 'xl:hidden lg:hidden md:block';
```
### 5. 字体大小级联
使用父元素字体大小控制子元素(特别是图标)的尺寸:
```typescript
className = 'xl:text-[48px] lg:text-[40px] md:text-[30px] ...';
```
子元素使用 `text-[100%]` 继承父元素字体大小,实现统一缩放。
## 边界
### 输入
- **Props**:
- `children`:React.ReactNode(定义但未使用,保留用于扩展)
- **Redux State**:
- `currentKey`:当前业务流程标识(来自 `BusinessFlowSlice`)
- **配置**:
- `pageLayoutConfig`:页面布局配置(品牌/状态栏位置)
### 输出
- **渲染输出**:完整的应用布局结构,包含:
- 品牌区域(Logo)
- 状态栏(磁盘、电池、WiFi、热容量)
- 导航菜单(根据屏幕尺寸选择不同形式)
- 内容区域(根据 currentKey 渲染对应页面)
- **事件派发**:
- `setBusinessFlow(key)`:更新业务流程状态
### 职责边界
#### 负责
- ✅ 整体布局结构定义
- ✅ 响应式适配逻辑
- ✅ 导航切换事件处理
- ✅ 页面组件渲染
- ✅ 布局配置应用
#### 不负责
- ❌ 具体页面的业务逻辑(由各页面组件负责)
- ❌ 状态栏数据获取(使用静态数据,实际数据由 StatusBar 组件处理)
- ❌ 用户权限验证(由上层路由或页面组件处理)
- ❌ 国际化内容翻译(TabBar 的文本是硬编码的)
## 涉及概念
### 1. 响应式布局(Responsive Layout)
通过 CSS 媒体查询和响应式工具类,使页面在不同屏幕尺寸下有不同表现。
**实现方式**:
- Ant Design 的 Grid 系统(Col 组件的 xl/lg/md/sm/xs 属性)
- Tailwind CSS 的响应式前缀(xl:/lg:/md:/sm:/xs:)
### 2. Grid 系统
将页面分为 24 列,通过 `Col` 组件的 `span` 值控制宽度。
**示例**:
```typescript
// 大屏占4列,小屏隐藏
// 大屏占20列,小屏隐藏
```
### 3. 映射表模式(Map Pattern)
使用对象字面量建立 key-value 映射,替代多个 if-else 或 switch 语句。
**优势**:
- 代码更简洁易读
- 易于维护和扩展
- 性能更好(O(1) 查找)
### 4. 状态驱动视图(State-Driven View)
视图完全由状态决定,状态改变自动触发视图更新。
**流程**:
```
用户点击导航 → dispatch(setBusinessFlow) → currentKey 更新 → 组件重新渲染 → 显示新页面
```
### 5. 条件渲染(Conditional Rendering)
根据条件决定是否渲染某个组件或元素。
**方式**:
- 逻辑与运算符:`{condition && }`
- 三元运算符:`{condition ? : }`
- CSS 类名控制:`className="xl:block sm:hidden"`
### 6. Flexbox 布局
使用 CSS Flexbox 实现灵活的布局方式。
**关键属性**:
- `flex: 1`:占据剩余空间
- `display: flex`:启用 flex 布局
- `justify-end`:主轴末端对齐
- `items-center`:交叉轴居中对齐
### 7. 配置化(Configuration)
将可变的参数提取到配置文件,提高代码的可维护性和灵活性。
**示例**:
```typescript
// 配置文件
export const pageLayoutConfig = {
brandAndStatusPosition: 'top' // 或 'bottom'
};
// 使用配置
{pageLayoutConfig.brandAndStatusPosition === 'top' && ...
}
```
### 8. 组件组合(Component Composition)
将大型组件拆分为多个小型、专注的组件,通过组合构建完整功能。
**本文件中的组件组合**:
- `NavMenu`:侧边导航菜单
- `NavbarFloat`:浮动导航菜单
- `StatusBar`:状态栏
- `TabBar`:底部标签栏
- 各个页面组件(RegisterPage、ExamPage 等)
## 注意事项
### 1. 硬编码问题
- **状态栏数据**:使用了硬编码的静态数据
```typescript
const status: StatusBarProps = {
diskStatus: 'available',
batteryLevel: 0,
wifiStrength: 0,
heatCapacity: 0,
};
```
**改进建议**:应该从实际的状态或 Redux store 中获取
- **TabBar 文本**:未使用国际化
```typescript
```
**改进建议**:应该使用 i18n 系统
### 2. 未使用的 Props
`children` prop 被定义但未使用,可能是为了未来扩展预留。
### 3. 重复代码
品牌和状态区域的代码重复了两次(top 和 bottom 位置),可以提取为独立组件。
### 4. TODO 项
代码中存在 TODO 注释,需要后续完善:
- MeButton 的登录状态和头像应该从实际状态获取
### 5. 响应式字体大小策略
通过顶层 Layout 设置字体大小,子元素使用 `text-[100%]` 继承,实现整体缩放。这是一个巧妙的设计,但需要确保所有子组件都支持这种方式。
## 相关文件
- `src/layouts/NavMenu.tsx`:侧边导航菜单组件
- `src/layouts/NavbarFloat.tsx`:浮动导航菜单组件
- `src/layouts/StateBar.tsx`:状态栏组件
- `src/states/BusinessFlowSlice.ts`:业务流程状态切片
- `src/config/pageLayout.ts`:页面布局配置
- `src/pages/*`:各个页面组件