BasicLayout.tsx.md 7.9 KB

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 与页面组件的映射关系:

const contentMap = {
  exam: <ExamPage />,
  process: <ImageProcessingPage />,
  view: <ImageProcessingPage />,
  register: <RegisterPage />,
  worklist: <WorklistPage />,
  // ... 其他页面
};

优势

  • 集中管理所有页面路由
  • 易于添加新页面
  • 避免复杂的条件判断

2. 状态驱动渲染

通过 Redux 的 currentKey 状态控制当前显示的页面:

const currentKey = useSelector(
  (state: RootState) => state.BusinessFlow.currentKey
);

// 渲染对应页面
{
  contentMap[currentKey];
}

3. 配置化布局

从配置文件读取布局参数,支持动态调整:

{pageLayoutConfig.brandAndStatusPosition === 'top' && (
  <Row>品牌和状态区域</Row>
)}

4. 响应式导航策略

  • 大屏(xl/lg):使用侧边栏 NavMenu
  • 中屏(md):使用浮动菜单 NavbarFloat
  • 小屏(sm/xs):使用底部 TabBar

通过 Tailwind CSS 的响应式工具类实现:

className = 'xl:hidden lg:hidden md:block';

5. 字体大小级联

使用父元素字体大小控制子元素(特别是图标)的尺寸:

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 值控制宽度。

示例

<Col xl={4} lg={4} md={5} sm={0} xs={0}>  // 大屏占4列,小屏隐藏
<Col xl={20} lg={20} md={19} sm={0} xs={0}>  // 大屏占20列,小屏隐藏

3. 映射表模式(Map Pattern)

使用对象字面量建立 key-value 映射,替代多个 if-else 或 switch 语句。

优势

  • 代码更简洁易读
  • 易于维护和扩展
  • 性能更好(O(1) 查找)

4. 状态驱动视图(State-Driven View)

视图完全由状态决定,状态改变自动触发视图更新。

流程

用户点击导航 → dispatch(setBusinessFlow) → currentKey 更新 → 组件重新渲染 → 显示新页面

5. 条件渲染(Conditional Rendering)

根据条件决定是否渲染某个组件或元素。

方式

  • 逻辑与运算符:{condition && <Component />}
  • 三元运算符:{condition ? <A /> : <B />}
  • CSS 类名控制:className="xl:block sm:hidden"

6. Flexbox 布局

使用 CSS Flexbox 实现灵活的布局方式。

关键属性

  • flex: 1:占据剩余空间
  • display: flex:启用 flex 布局
  • justify-end:主轴末端对齐
  • items-center:交叉轴居中对齐

7. 配置化(Configuration)

将可变的参数提取到配置文件,提高代码的可维护性和灵活性。

示例

// 配置文件
export const pageLayoutConfig = {
  brandAndStatusPosition: 'top' // 或 'bottom'
};

// 使用配置
{pageLayoutConfig.brandAndStatusPosition === 'top' && <Row>...</Row>}

8. 组件组合(Component Composition)

将大型组件拆分为多个小型、专注的组件,通过组合构建完整功能。

本文件中的组件组合

  • NavMenu:侧边导航菜单
  • NavbarFloat:浮动导航菜单
  • StatusBar:状态栏
  • TabBar:底部标签栏
  • 各个页面组件(RegisterPage、ExamPage 等)

注意事项

1. 硬编码问题

  • 状态栏数据:使用了硬编码的静态数据
  const status: StatusBarProps = {
    diskStatus: 'available',
    batteryLevel: 0,
    wifiStrength: 0,
    heatCapacity: 0,
  };

改进建议:应该从实际的状态或 Redux store 中获取

  • TabBar 文本:未使用国际化 typescript <TabBar.Item title="患者管理" ... /> 改进建议:应该使用 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/*:各个页面组件