---
title: 设计文档
order: 2
category: pro
---

# PisellGridPro 设计文档

## 设计思路

PisellGridPro 是一个面向后台管理系统的标准化页面布局组件，旨在解决以下核心问题：

### 核心痛点

1. **布局不统一**: 不同页面的布局结构各异，缺乏统一规范
2. **重复代码**: 每个页面都需要编写相似的布局代码
3. **维护困难**: 布局代码分散在各个页面，难以统一修改
4. **视觉不一致**: 缺少统一的布局组件导致页面风格不统一
5. **响应式困难**: 手动处理响应式布局耗时且容易出错

### 解决方案

PisellGridPro 通过 **组件化 + 插槽模式** 提供了标准化的页面布局方案：

```
┌───────────────────────────────────────────────────┐
│                  PisellGridPro                    │
│         (Flex 垂直布局容器)                         │
│                                                   │
│  ┌─────────────────────────────────────────────┐ │
│  │  Header (flex-shrink: 0)                    │ │
│  │  标题栏、操作按钮                              │ │
│  └─────────────────────────────────────────────┘ │
│                                                   │
│  ┌─────────────────────────────────────────────┐ │
│  │  ToolBar (flex-shrink: 0)                   │ │
│  │  工具栏、标签页、筛选器                         │ │
│  └─────────────────────────────────────────────┘ │
│                                                   │
│  ┌─────────────────────────────────────────────┐ │
│  │  DataCard (flex-shrink: 0)                  │ │
│  │  统计数据卡片                                  │ │
│  └─────────────────────────────────────────────┘ │
│                                                   │
│  ┌─────────────────────────────────────────────┐ │
│  │  View (flex: 1, overflow: hidden)           │ │
│  │  主内容区域（内置滚动）                         │ │
│  │                                             │ │
│  │  ↕ (scrollable)                             │ │
│  │                                             │ │
│  └─────────────────────────────────────────────┘ │
│                                                   │
│  ┌─────────────────────────────────────────────┐ │
│  │  Footer (flex-shrink: 0)                    │ │
│  │  底部操作栏、分页                              │ │
│  └─────────────────────────────────────────────┘ │
│                                                   │
└───────────────────────────────────────────────────┘
```

## 架构设计

### 1. 主容器设计 (PisellGridPro)

**职责**：提供页面级的垂直布局容器

**核心样式**：

```css
.pisell-grid-pro {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100vh; /* 占满视口高度 */
  background: #ffffff;
  overflow: hidden; /* 防止整体滚动 */
  padding: 0 24px;

  > * {
    flex-shrink: 0; /* 子组件默认不收缩 */
  }
}
```

**设计理念**：

- **Flex 布局**: 使用 flexbox 提供灵活的垂直布局能力
- **全屏容器**: 默认占满视口，确保页面布局的完整性
- **防止收缩**: 子组件默认 flex-shrink: 0，保证固定区域不会被压缩
- **统一间距**: 默认左右 24px 内边距，保证内容不贴边

**扩展点**：

- 支持通过 style 自定义高度、背景色、内边距
- 支持通过 className 添加自定义样式

### 2. Header 组件设计

**职责**：页面标题栏，展示页面核心信息和操作入口

**布局结构**：

```
┌────────────────────────────────────────────────────┐
│  ┌──────────────────┐              ┌────────────┐ │
│  │  Title + Badge   │              │  Actions   │ │
│  │  Subtitle        │              │  List      │ │
│  └──────────────────┘              └────────────┘ │
│   (左侧内容)                          (右侧操作)   │
└────────────────────────────────────────────────────┘
```

**核心属性**：

```
interface HeaderProps {
  title?: ReactNode;        // 主标题
  badge?: ReactNode;        // 标题旁徽章（状态标识、数量等）
  subTitle?: ReactNode;     // 副标题（补充说明）
  actionsList?: ReactNode;  // 右侧操作按钮
  className?: string;
  style?: CSSProperties;
}
```

**设计理念**：

- **左右分布**: 左侧信息展示，右侧操作按钮
- **层次分明**: 主标题 + 徽章 + 副标题的层次结构
- **灵活插槽**: 所有内容都是 ReactNode，支持自定义渲染
- **语义清晰**: 属性命名明确表达用途

**典型用例**：

```
// 基础标题
<Header title="用户管理" />

// 带徽章的标题（显示状态或数量）
<Header
  title="订单列表"
  badge={<Badge count={5} />}
/>

// 完整信息
<Header
  title="销售报表"
  badge={<Tag color="blue">Beta</Tag>}
  subTitle="实时销售数据统计"
  actionsList={
    <>
      <Button>导出</Button>
      <Button type="primary">新建</Button>
    </>
  }
/>
```

### 3. ToolBar 组件设计

**职责**：工具栏，提供标签页、筛选、排序等交互功能

**布局结构**：

```
┌────────────────────────────────────────────────────┐
│  Tabs (如果有)                                      │
├────────────────────────────────────────────────────┤
│  ┌──────────────────┐       ┌──────────────────┐  │
│  │  Top Left        │       │  Top Right       │  │
│  └──────────────────┘       └──────────────────┘  │
├────────────────────────────────────────────────────┤
│  ┌──────────────────┐       ┌──────────────────┐  │
│  │  Bottom Left     │       │  Bottom Right    │  │
│  └──────────────────┘       └──────────────────┘  │
└────────────────────────────────────────────────────┘
```

**核心属性**：

```
interface ToolBarProps {
  tabs?: ReactNode;           // 标签页
  topLeft?: ReactNode;        // 顶部左侧
  topRight?: ReactNode;       // 顶部右侧
  bottomLeft?: ReactNode;     // 底部左侧
  bottomRight?: ReactNode;    // 底部右侧
  className?: string;
  style?: CSSProperties;
}
```

**设计理念**：

- **多层布局**: 支持标签页 + 上下两行共 5 个插槽位置
- **左右对齐**: 每行都是左右对齐布局，符合常见 UI 模式
- **灵活组合**: 各个插槽独立，可按需使用
- **非语义化命名**: 使用位置命名（topLeft 等）而非功能命名，提供更大的灵活性

**设计权衡**：

- **为什么不用语义化命名？**
  - 如果使用 `filters`、`sorters` 等语义化命名，会限制使用场景
  - 位置命名（topLeft 等）更灵活，业务方可以放置任何内容
  - 例如：topLeft 可以是筛选器、搜索框、批量操作等

**典型用例**：

```
// 标签页 + 搜索
<ToolBar
  tabs={<Tabs items={tabItems} />}
  topRight={<SearchBar />}
/>

// 筛选器 + 排序 + 视图切换
<ToolBar
  topLeft={<FilterGroup />}
  topRight={<SortDropdown />}
  bottomRight={<ViewSwitcher />}
/>

// 完整工具栏
<ToolBar
  tabs={<Tabs items={tabItems} />}
  topLeft={<SearchBar />}
  topRight={
    <>
      <Button>筛选</Button>
      <Button>排序</Button>
    </>
  }
  bottomLeft={<BatchActions />}
  bottomRight={<Pagination simple />}
/>
```

### 4. DataCard 组件设计

**职责**：展示统计数据卡片，提供数据概览

**布局结构**：

```
┌────────┬────────┬────────┬────────┐
│ Card 1 │ Card 2 │ Card 3 │ Card 4 │
│        │        │        │        │
│ Title  │ Title  │ Title  │ Title  │
│ Value  │ Value  │ Value  │ Value  │
│ Compare│ Compare│ Compare│ Compare│
└────────┴────────┴────────┴────────┘
```

**核心类型**：

```
interface DataCardProps {
  dataItems?: StatCardItem[];  // 卡片数据列表
  className?: string;
  style?: CSSProperties;
}

interface StatCardItem {
  key: string;                    // 唯一标识
  title: ReactNode;               // 卡片标题
  value: ReactNode;               // 主要数值
  compareValue?: ReactNode;       // 对比数值
  trend?: 'up' | 'down';          // 趋势方向
  comparePrefix?: string;         // 对比前缀
  showCompare?: boolean;          // 是否显示对比
  onClick?: () => void;           // 点击回调
  className?: string;
  style?: CSSProperties;
}
```

**设计理念**：

- **数据驱动**: 通过 dataItems 数组驱动卡片渲染
- **趋势可视化**: 支持 up/down 趋势，自动显示箭头和颜色
- **灵活对比**: 支持自定义对比文本和前缀
- **交互支持**: 支持点击事件，可跳转详情或触发操作
- **空状态处理**: dataItems 为空时不渲染任何内容

**StatCard 子组件设计**：

```
┌─────────────────────┐
│  Title              │  ← 标题
│                     │
│  $45,231            │  ← 主数值（大字号）
│                     │
│  v.s. pre +20% ↑   │  ← 对比信息（绿色/红色）
└─────────────────────┘
```

**样式设计**：

```css
.stat-card {
  /* 基础样式 */
  padding: 16px;
  background: #fff;
  border-radius: 4px;
  cursor: default;

  /* 可点击状态 */
  &-clickable {
    cursor: pointer;
    transition: all 0.3s;

    &:hover {
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
      transform: translateY(-2px);
    }
  }

  /* 趋势颜色 */
  .trend-up {
    color: #52c41a; // 绿色 - 上升
  }

  .trend-down {
    color: #ff4d4f; // 红色 - 下降
  }
}
```

**典型用例**：

```
// 基础数据卡片
<DataCard
  dataItems={[
    {
      key: '1',
      title: '总销售额',
      value: '$126,560',
    },
  ]}
/>

// 带趋势的卡片
<DataCard
  dataItems={[
    {
      key: '1',
      title: '总订单',
      value: '1,234',
      compareValue: '+12%',
      trend: 'up',
      comparePrefix: '较上月',
    },
    {
      key: '2',
      title: '待处理',
      value: '56',
      compareValue: '-5',
      trend: 'down',
    },
  ]}
/>

// 可点击的卡片
<DataCard
  dataItems={[
    {
      key: '1',
      title: '今日收入',
      value: '$8,846',
      compareValue: '+8.2%',
      trend: 'up',
      onClick: () => router.push('/revenue-detail'),
    },
  ]}
/>
```

### 5. View 组件设计

**职责**：主内容区域，提供滚动能力

**核心特性**：

- **占据剩余空间**: 通过 flex: 1 自动占据剩余高度
- **内置滚动**: 集成 PisellScrollView，自动处理滚动
- **溢出隐藏**: overflow: hidden 防止影响整体布局

**样式设计**：

```css
.pisell-grid-pro-view {
  flex: 1; /* 占据剩余空间 */
  overflow: hidden; /* 隐藏溢出 */
  min-height: 0; /* 解决 flex 布局子元素高度问题 */
}
```

**设计理念**：

- **自动伸缩**: View 会自动占据 Header、ToolBar、DataCard、Footer 之外的所有空间
- **滚动隔离**: 只有 View 内部可滚动，其他区域固定
- **性能优化**: 使用 PisellScrollView 提供虚拟滚动等性能优化

**典型用例**：

```
// 表格内容
<View>
  <Table dataSource={data} columns={columns} />
</View>

// 卡片列表
<View>
  <List dataSource={items} renderItem={(item) => <Card {...item} />} />
</View>

// 自定义内容
<View>
  <div>
    <Charts />
    <Description />
    <Comments />
  </div>
</View>
```

### 6. Footer 组件设计

**职责**：页脚区域，放置固定在底部的操作

**设计理念**：

- **简单容器**: 提供一个固定在底部的容器
- **完全自定义**: 内部内容完全由业务控制
- **常见用途**: 分页、批量操作确认、保存取消按钮等

**典型用例**：

```
// 分页
<Footer>
  <Pagination total={100} />
</Footer>

// 批量操作
<Footer>
  <div style={{ display: 'flex', justifyContent: 'space-between' }}>
    <div>已选择 10 项</div>
    <Space>
      <Button>取消</Button>
      <Button type="primary" danger>批量删除</Button>
    </Space>
  </div>
</Footer>

// 表单操作
<Footer>
  <Space>
    <Button onClick={handleCancel}>取消</Button>
    <Button type="primary" onClick={handleSubmit}>保存</Button>
  </Space>
</Footer>
```

## 复合组件模式设计

### 为什么使用复合组件？

PisellGridPro 使用复合组件（Compound Component）模式，而不是通过 props 传递子组件：

```
// ❌ 不推荐：通过 props 传递
<PisellGridPro
  header={{ title: '标题', actions: [...] }}
  toolbar={{ topLeft: ..., topRight: ... }}
  dataCard={{ items: [...] }}
  view={<Table />}
  footer={<Pagination />}
/>

// ✅ 推荐：复合组件模式
<PisellGridPro>
  <PisellGridPro.Header title="标题" actionsList={...} />
  <PisellGridPro.ToolBar topLeft={...} topRight={...} />
  <PisellGridPro.DataCard dataItems={[...]} />
  <PisellGridPro.View>
    <Table />
  </PisellGridPro.View>
  <PisellGridPro.Footer>
    <Pagination />
  </PisellGridPro.Footer>
</PisellGridPro>
```

**复合组件模式的优势**：

1. **更直观**: JSX 结构直接反映页面布局
2. **更灵活**: 可以按需使用子组件，不需要的直接不写
3. **类型安全**: 每个子组件有独立的 TypeScript 类型
4. **易于扩展**: 添加新的子组件不影响现有 API
5. **代码可读性好**: 一眼就能看出页面结构

### 实现方式

```
// 定义复合组件类型
interface PisellGridProType extends React.FC<PisellGridProps> {
  Header: typeof Header;
  ToolBar: typeof ToolBar;
  DataCard: typeof DataCard;
  View: typeof View;
  Footer: typeof Footer;
}

// 挂载子组件
const PisellGridPro = PisellGridProComponent as PisellGridProType;

PisellGridPro.Header = Header;
PisellGridPro.ToolBar = ToolBar;
PisellGridPro.DataCard = DataCard;
PisellGridPro.View = View;
PisellGridPro.Footer = Footer;

export default PisellGridPro;
```

## 布局计算逻辑

### 高度分配

```
总高度：100vh

Header:      auto (内容撑开，不收缩)
ToolBar:     auto (内容撑开，不收缩)
DataCard:    auto (内容撑开，不收缩)
View:        flex: 1 (占据剩余空间)
Footer:      auto (内容撑开，不收缩)

计算公式：
View 高度 = 100vh - Header高度 - ToolBar高度 - DataCard高度 - Footer高度 - 容器padding
```

### 为什么 View 需要 flex: 1？

```css
/* 错误示例：View 没有 flex: 1 */
.pisell-grid-pro-view {
  height: auto;
}
/* 问题：View 会被内容撑开，超出容器高度，导致整体滚动 */

/* 正确示例：View 使用 flex: 1 */
.pisell-grid-pro-view {
  flex: 1;
  overflow: hidden;
}
/* 效果：View 占据剩余空间，内部滚动，外部固定 */
```

## 响应式设计

### 容器响应式

```css
.pisell-grid-pro {
  padding: 0 24px;

  @media (max-width: 768px) {
    padding: 0 16px; /* 移动端减小内边距 */
  }
}
```

### DataCard 响应式

```css
.pisell-grid-pro-datacard {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;

  /* 自动适配列数：
   * - 大屏幕：4列
   * - 中屏幕：2-3列
   * - 小屏幕：1列
   */
}
```

### Header 响应式

```css
.pisell-grid-pro-header {
  display: flex;
  align-items: center;
  justify-content: space-between;

  @media (max-width: 768px) {
    flex-direction: column; /* 移动端垂直布局 */
    align-items: flex-start;

    .pisell-grid-pro-header-actions {
      margin-top: 12px;
      width: 100%;
    }
  }
}
```

## 设计优势

### 1. 统一的视觉规范

所有使用 PisellGridPro 的页面都遵循相同的布局结构，保证了视觉一致性。

### 2. 开发效率提升

- **减少重复代码**: 不需要每个页面都写布局代码
- **快速搭建**: 几行代码即可完成页面框架
- **专注业务**: 开发者可以专注于业务逻辑，而非布局细节

### 3. 易于维护

- **集中管理**: 布局逻辑集中在组件内部
- **统一修改**: 修改组件即可影响所有页面
- **版本升级**: 组件升级自动应用到所有使用方

### 4. 灵活可扩展

- **可选组件**: 所有子组件都是可选的
- **插槽模式**: 支持自定义内容
- **样式定制**: 支持 className 和 style 定制

### 5. 响应式支持

- **自动适配**: 内置响应式逻辑
- **移动端友好**: 支持移动端布局调整

## 设计权衡

### 1. 复合组件 vs Props 配置

**选择**：复合组件模式

**权衡**：

- **优势**：更直观、更灵活、类型安全
- **劣势**：代码略长（但更清晰）
- **结论**：复合组件模式带来的开发体验提升远大于代码长度的增加

### 2. 固定布局 vs 自由布局

**选择**：固定布局顺序

**权衡**：

- **优势**：统一规范、降低学习成本
- **劣势**：灵活性稍弱
- **结论**：标准化布局更重要，特殊需求可以不使用该组件

### 3. 高度自适应 vs 固定高度

**选择**：高度自适应（100vh）

**权衡**：

- **优势**：自动占满屏幕，无需手动计算
- **劣势**：某些场景可能需要自定义高度
- **结论**：大部分场景都是全屏布局，支持通过 style 自定义高度

### 4. 内置滚动 vs 外部滚动

**选择**：View 内置滚动，其他区域固定

**权衡**：

- **优势**：符合常见 UI 模式，用户体验好
- **劣势**：需要正确设置高度（flex: 1）
- **结论**：固定头尾、内容滚动是后台系统的标准模式

## 未来规划

### 1. 主题定制

支持通过 CSS 变量定制主题：

```css
.pisell-grid-pro {
  --header-height: auto;
  --header-bg: #fff;
  --toolbar-bg: #fafafa;
  --datacard-gap: 16px;
  --view-bg: #fff;
  --footer-height: auto;
}
```

### 2. 预设布局模板

提供常见布局的预设模板：

```
// 列表页面模板
<PisellGridPro.ListTemplate
  title="用户列表"
  toolbar={<SearchBar />}
  dataSource={users}
/>

// 详情页面模板
<PisellGridPro.DetailTemplate
  title="订单详情"
  data={orderData}
/>
```

### 3. 布局状态管理

支持布局状态的保存和恢复：

```
const [layoutState, setLayoutState] = useLayoutState('user-list-page');

<PisellGridPro layoutState={layoutState} onLayoutChange={setLayoutState}>
  {/* 保存 ToolBar 展开状态、DataCard 显隐等 */}
</PisellGridPro>
```

### 4. 动画支持

支持组件展开/收起动画：

```
<PisellGridPro.DataCard
  collapsible
  defaultCollapsed={false}
  dataItems={items}
/>
```

### 5. 多端适配增强

更好的移动端、平板端适配：

```
<PisellGridPro
  breakpoints={{
    mobile: { padding: 12 },
    tablet: { padding: 16 },
    desktop: { padding: 24 },
  }}
>
```

## 总结

PisellGridPro 通过标准化的布局设计和复合组件模式，为后台管理系统提供了：

1. **统一规范**: 所有页面遵循相同的布局结构
2. **开发效率**: 快速搭建页面，减少重复代码
3. **灵活组合**: 各个子组件可按需使用
4. **易于维护**: 集中管理布局逻辑
5. **扩展性强**: 支持自定义和扩展

核心设计原则：

- **标准化优先**: 提供统一的布局规范
- **灵活性兼顾**: 支持按需组合和自定义
- **用户体验**: 固定头尾、内容滚动的标准模式
- **开发体验**: 直观的 API 和完善的类型支持

### 设计资源

- [Figma 设计稿](https://www.figma.com/design/pM8Ho6d7kCMv9vIBvFHUlj/Pisell-2.0-Component-Library?node-id=12890-90810)
- [文档规范](https://m1ed09stz4r.feishu.cn/wiki/G48gwDUR0iTfjYki7QUcg43znBe)
