---
title: Tuffex 组合界面教程
description: 使用 Tuffex 组件搭建可审阅、可截图验证的后台页面切片
syncStatus: migrated
verified: true
---

# Tuffex 组合界面教程

本教程面向 Tuff / Dashboard / Admin 页面：目标不是堆组件，而是把页面切成“操作区 → 状态区 → 数据区”，让用户能快速判断当前状态并完成动作。

## 组件套件与引入

Tuffex 按三套件组织：基础组件（`base`）、进阶套件（`pro`）与 AI 套件（`ai`）。除整包引入外，可从分类入口按套件引入，便于按需组织依赖：

```ts
import { TxButton, TxDataTable } from '@talex-touch/tuffex/base'
import { TxCommandPalette, TxLiquid } from '@talex-touch/tuffex/pro'
import { ChatList, TxPromptBar } from '@talex-touch/tuffex/ai'
```

三个入口的导出并集与主入口 `@talex-touch/tuffex` 完全一致；样式照常从 `@talex-touch/tuffex/style.css` 全量引入，或按组件的 `style.css` 按需引入。各组件的套件归属见[组件总览](/docs/dev/components)。

## 1. 页面分组

| 分组 | 推荐组件 | 说明 |
|------|----------|------|
| 操作区 | `TxButton`、`TuffInput`、`TxSearchInput`、`TxSearchSelect`、`TuffSwitch` | 承载搜索、筛选、刷新、发布、同步等即时操作 |
| 状态区 | `TxStatusBadge`、`TxTag`、`TxProgressBar` | 展示审核、同步、发布、容量等状态 |
| 数据区 | `TxDataTable`、`TxPagination`、`TxEmptyState`、`TxSearchEmpty`、`TxSkeleton`、`TxLoadingState` | 展示记录、选择行、分页、空态和加载态 |
| 反馈区 | `TxToastHost`、`TxTooltip`、`TxLoadingOverlay`、`TxSpinner` | 展示任务结果、解释动作、阻断局部刷新和行内等待 |
| 趋势区 | Dashboard 图表组件 | 趋势图优先复用图表封装，避免手写一次性 SVG |
| 权限编排区 | `TxTree`、`TxTreeSelect`、`TxTransfer`、`TxTimeline` | 选择权限域、归属团队、资源授权和审计进度 |
| 导航配置区 | `TxTabs`、`TxDropdownMenu`、`TxPopover`、`TxDrawer` | 设置页用 Tabs 固定分区，轻操作进菜单/浮层，高密度配置进抽屉 |
| 发布配置区 | `TxCascader`、`TxFlatSelect`、`TxSegmentedSlider`、`TxSlider`、`TxTagInput` | 选择发布范围、包格式、发布模式、风险档位、灰度比例和短标签 |

## 2. 最小可运行片段

::TuffDemoWrapper{demo="ComponentsWorkflowPanelDemo" code-lang="vue" title="发布工作台组合" description="一个截图可验证的 Dashboard 组合片段。"}
---
code: |
  <script setup lang="ts">
  import type { DataTableColumn } from '@talex-touch/tuffex'
  import { computed, ref } from 'vue'

  interface Row {
    id: number
    task: string
    owner: string
    status: string
    score: number
  }

  const query = ref('')
  const selectedKeys = ref<Array<number | string>>([1])
  const rows: Row[] = [
    { id: 1, task: '组件截图核验', owner: 'Tuff', status: 'review', score: 84 },
    { id: 2, task: 'API 表格补齐', owner: 'Tuffex', status: 'ready', score: 92 },
    { id: 3, task: '暗色模式回归', owner: 'QA', status: 'failed', score: 48 },
  ]
  const columns: DataTableColumn<Row>[] = [
    { key: 'task', title: '任务' },
    { key: 'owner', title: '负责人' },
    { key: 'status', title: '状态' },
    { key: 'score', title: '评分', sortable: true },
  ]
  const filteredRows = computed(() => rows.filter(row => row.task.includes(query.value) || row.owner.includes(query.value)))
  </script>

  <template>
    <section class="grid gap-3">
      <TuffInput v-model="query" placeholder="搜索任务" prefix-icon="i-carbon-search" clearable />
      <TxProgressBar :percentage="84" status="success" show-text />
      <TxDataTable v-model:selected-keys="selectedKeys" :columns="columns" :data="filteredRows" row-key="id" selectable />
    </section>
  </template>
---
::

## 3. 搜索与筛选路径

列表页不要把“输入关键词”“选择范围”“没有结果”拆成三个孤立区域。推荐把 `TxSearchInput`、`TxSearchSelect` 与 `TxSearchEmpty` 放进同一个筛选容器，保证用户能清楚看到当前条件、匹配数量和恢复动作。

::TuffDemoWrapper{demo="ComponentsSearchFiltersDemo" code-lang="vue" title="后台筛选工具栏" description="关键词、筛选范围与搜索空态共用同一条恢复路径。"}
---
code: |
  <script setup lang="ts">
  import { computed, ref } from 'vue'

  const query = ref('')
  const selectedScope = ref<string | number>('all')
  const scopeOptions = [
    { value: 'all', label: '全部' },
    { value: 'docs', label: '文档' },
    { value: 'tasks', label: '任务' },
  ]
  const filteredRecords = computed(() => (query.value ? [] : scopeOptions))
  </script>

  <template>
    <section class="grid gap-3">
      <TxSearchInput v-model="query" remote placeholder="搜索插件 / 文档 / 任务" />
      <TxSearchSelect v-model="selectedScope" :options="scopeOptions" placeholder="筛选范围" />
      <TxSearchEmpty v-if="!filteredRecords.length" surface="card" />
    </section>
  </template>
---
::

## 4. 运营状态首屏

Dashboard / Admin 页面通常先让用户判断“系统是否健康”。首屏建议按下面顺序组织：

| 层级 | 组件 | 使用要点 |
|------|------|----------|
| 标题层 | 原生标题 + `TxButton` | 标题说明当前运营范围，右侧只放一个主刷新/发布操作 |
| 状态层 | `TxStatusBadge` | 用文字表达状态，不只依赖颜色 |
| 指标层 | `TxStatCard` | 默认展示数字，健康度/容量使用 `variant="progress"` |
| 进度层 | `TxProgressBar` | 已知百分比用 `percentage`，未知时长用 `loading` |

::TuffDemoWrapper{demo="ComponentsOperationsStatusDemo" code-lang="vue" title="运营状态面板" description="适合作为后台页面首屏的状态、指标和进度组合。"}
---
code: |
  <template>
    <section class="grid gap-3">
      <TxStatusBadge text="审阅完成" status="success" />
      <TxStatCard
        variant="progress"
        value="99.9%"
        label="API 可用率"
        meta="正常"
        :progress="99"
      />
      <TxProgressBar :percentage="86" status="success" show-text />
    </section>
  </template>
---
::

## 5. 趋势图区

后台页的趋势图优先复用 `DashboardSparklineChart` / `DashboardMetricChart`，不要在页面里写一次性 `svg` 折线。这样可以统一 tooltip、暗色主题、ResizeObserver 和空态表现。

::TuffDemoWrapper{demo="ComponentsDashboardSparklineDemo" code-lang="vue" title="后台趋势图" description="ECharts 封装后的轻量趋势图。"}
---
code: |
  <script setup lang="ts">
  import DashboardSparklineChart from '~/components/dashboard/DashboardSparklineChart.client.vue'
  </script>

  <template>
    <DashboardSparklineChart
      :values="[18, 24, 21, 36, 42, 38, 54]"
      color="var(--tx-color-primary, #409eff)"
      show-grid
    />
  </template>
---
::

## 6. 数据恢复路径

每个数据面板都要同时设计三种恢复路径：加载中、无数据、请求失败。它们应占用同一个容器，避免用户看到页面跳动或重复占位。

::TuffDemoWrapper{demo="ComponentsRecoveryStatesDemo" code-lang="vue" title="后台恢复状态" description="加载、空态、错误态共用一个数据容器。"}
---
code: |
  <template>
    <section class="grid gap-3">
      <TxLoadingState title="正在加载规则" surface="card" />
      <TxEmptyState variant="no-data" title="还没有自动化规则" surface="card" />
      <TxErrorState title="规则加载失败" surface="card" />
    </section>
  </template>
---
::

## 7. 数据列表与分页

后台数据区应优先把“表格主体、选择状态、分页、加载占位”放在同一块工作区里。表格不要自带临时状态文案，分页不要脱离表格底部，长耗时加载用骨架保持空间。

::TuffDemoWrapper{demo="ComponentsDataOperationsDemo" code-lang="vue" title="数据运维面板" description="表格选择、分页和骨架加载共用一个后台数据区。"}
---
code: |
  <template>
    <section class="grid gap-3">
      <TxDataTable :columns="columns" :data="pagedRows" row-key="id" selectable />
      <TxPagination v-model:current-page="page" :total="rows.length" :page-size="4" show-info />
      <TxSkeleton :loading="true" :lines="3" />
    </section>
  </template>
---
::


## 8. 任务反馈路径

后台任务反馈需要把“动作解释、结果提示、局部阻断、行内等待”拆开：`TxTooltip` 解释按钮，`TxToastHost` 展示短反馈，`TxLoadingOverlay` 阻断正在刷新的数据块，`TxSpinner` 只用于没有百分比的短等待。

::TuffDemoWrapper{demo="ComponentsFeedbackTaskCenterDemo" code-lang="vue" title="后台任务反馈中心" description="Toast / Tooltip / LoadingOverlay / Spinner 的后台任务组合。"}
---
code: |
  <script setup lang="ts">
  import { toast } from '@talex-touch/tuffex/utils'
  import { ref } from 'vue'

  const syncing = ref(true)
  </script>

  <template>
    <section class="grid gap-3">
      <TxToastHost />
      <TxTooltip content="Tooltip 只解释当前动作。">
        <TxButton @click="toast({ title: '同步任务已排队', duration: 0 })">发送提示</TxButton>
      </TxTooltip>
      <TxLoadingOverlay :loading="syncing" text="正在刷新任务队列…">
        <TxSpinner :size="16" />
      </TxLoadingOverlay>
    </section>
  </template>
---
::

## 9. 权限编排路径

后台授权页需要先回答“授权哪个范围”，再回答“交给谁、给哪些资源、当前审计到哪一步”。推荐用 `TxTree` 放左侧权限域，`TxTreeSelect` 放归属团队，`TxTransfer` 管资源授权，`TxTimeline` 显示审计进度。

::TuffDemoWrapper{demo="ComponentsPermissionOrchestrationDemo" code-lang="vue" title="权限编排面板" description="Tree / TreeSelect / Transfer / Timeline 的后台授权组合。"}
---
code: |
  <script setup lang="ts">
  import { ref } from 'vue'

  const selectedScope = ref<string | number>('release')
  const ownerTeam = ref<string | number | undefined>('docs')
  const assignedKeys = ref<Array<string | number>>(['read-docs'])
  </script>

  <template>
    <section class="grid gap-3">
      <TxTree v-model="selectedScope" :nodes="scopeNodes" />
      <TxTreeSelect v-model="ownerTeam" :nodes="teamNodes" placeholder="归属团队" />
      <TxTransfer v-model="assignedKeys" :data="resources" />
      <TxTimeline>
        <TxTimelineItem title="分配资源" time="10:20" color="success" active />
      </TxTimeline>
    </section>
  </template>
---
::

## 10. 导航与配置壳层

后台设置页需要先回答“我在哪个分区”，再回答“当前能做什么操作”。推荐把一级分区固定在 `TxTabs`，把一次性操作放进 `TxDropdownMenu`，把短说明放进 `TxPopover`，把长配置放进 `TxDrawer`。

::TuffDemoWrapper{demo="ComponentsNavigationShellDemo" code-lang="vue" title="后台导航配置壳层" description="Tabs / DropdownMenu / Popover / Drawer 的后台设置页组合。"}
---
code: |
  <template>
    <section class="grid gap-3">
      <TxDropdownMenu>
        <template #trigger>
          <TxButton>发布操作</TxButton>
        </template>
        <TxDropdownItem>快速发布</TxDropdownItem>
      </TxDropdownMenu>
      <TxPopover>
        <template #reference>
          <TxButton variant="secondary">策略说明</TxButton>
        </template>
        浮层只放短说明和轻量动作。
      </TxPopover>
      <TxTabs placement="left" indicator-variant="pill">
        <TxTabItem name="总览" activation>总览配置</TxTabItem>
      </TxTabs>
      <TxDrawer :visible="false" title="发布策略" />
    </section>
  </template>
---
::

## 11. 发布策略配置

发布配置页要避免把所有字段堆进一个大表单。推荐先用 `TxCascader` 明确范围，再用 `TxFlatSelect` 做低噪音单选；离散风险给 `TxSegmentedSlider`，连续比例给 `TxSlider`，标签输入只放短元数据。

::TuffDemoWrapper{demo="ComponentsReleasePolicyDemo" code-lang="vue" title="发布策略配置" description="Cascader / FlatSelect / SegmentedSlider / Slider / TagInput 的后台发布配置组合。"}
---
code: |
  <script setup lang="ts">
  import { ref } from 'vue'

  const releasePath = ref(['desktop', 'stable', 'macos'])
  const packageFormat = ref('signed')
  const rolloutMode = ref('phased')
  const riskLevel = ref(2)
  const traffic = ref(35)
  const labels = ref(['nexus', 'verified'])
  const scopeOptions = [
    {
      value: 'desktop',
      label: '桌面端',
      children: [
        {
          value: 'stable',
          label: '稳定通道',
          children: [{ value: 'macos', label: 'macOS', leaf: true }],
        },
      ],
    },
  ]
  const riskSegments = [
    { value: 1, label: '低' },
    { value: 2, label: '中' },
    { value: 3, label: '高' },
    { value: 4, label: '冻结' },
  ]
  </script>

  <template>
    <section class="grid gap-3">
      <TxCascader v-model="releasePath" :options="scopeOptions" placeholder="发布范围" />
      <TxFlatSelect v-model="packageFormat" placeholder="包格式">
        <TxFlatSelectItem value="signed" label="签名构建" />
      </TxFlatSelect>
      <TxSegmentedSlider v-model="riskLevel" :segments="riskSegments" />
      <TxSlider v-model="traffic" :min="5" :max="100" :step="5" show-value />
      <TxTagInput v-model="labels" placeholder="输入标签后回车" />
    </section>
  </template>
---
::

## 12. 审阅检查清单

- **单一主动作**：每个面板只保留一个最高权重按钮，其余操作使用 `secondary` / `ghost`。
- **筛选闭环**：关键词、范围筛选、匹配数量和无结果恢复应来自同一组响应式数据。
- **分页贴合**：分页必须贴近列表底部，并与当前筛选、选择状态共用数据模型。
- **状态同步**：表格选择、进度条、徽标文字必须来自同一组响应式数据，避免重复常量。
- **空态可见**：没有数据时使用空态组件，不展示空白表格。
- **反馈分工**：Toast 只做短反馈，Tooltip 只做短解释，LoadingOverlay 只阻断局部刷新，Spinner 只表达短等待。
- **授权分工**：Tree 只表达层级范围，TreeSelect 只表达归属选择，Transfer 只表达资源分配，Timeline 只表达审计历史。
- **配置分层**：短操作进菜单，短说明进浮层，长配置进抽屉，避免一个 Popover 承担复杂表单。
- **发布策略分工**：Cascader 只表达范围，FlatSelect 只表达单选策略，SegmentedSlider 表达离散风险，Slider 表达连续比例，TagInput 只表达短元数据。
- **截图验证**：新增或改动 Demo 后，在本地 Tuff 页面打开并截图确认亮色、暗色、移动宽度至少一个关键状态。

## 13. 继续阅读

- [Tuffex 组件总览](../components/index.zh.mdc)
- [SearchInput 搜索输入框](../components/search-input.zh.mdc)
- [SearchSelect 搜索选择器](../components/search-select.zh.mdc)
- [SearchEmpty 搜索空态](../components/search-empty.zh.mdc)
- [StatCard 指标卡片](../components/stat-card.zh.mdc)
- [DataTable 数据表格](../components/data-table.zh.mdc)
- [Pagination 分页](../components/pagination.zh.mdc)
- [Skeleton 骨架屏](../components/skeleton.zh.mdc)
- [Cascader 级联选择](../components/cascader.zh.mdc)
- [FlatSelect 平铺下拉选择器](../components/flat-select.zh.mdc)
- [SegmentedSlider 分段滑块](../components/segmented-slider.zh.mdc)
- [Slider 滑块](../components/slider.zh.mdc)
- [TagInput 标签输入](../components/tag-input.zh.mdc)
- [Tree 树形](../components/tree.zh.mdc)
- [TreeSelect 树选择器](../components/tree-select.zh.mdc)
- [Transfer 穿梭框](../components/transfer.zh.mdc)
- [Timeline 时间线](../components/timeline.zh.mdc)
- [LayoutSkeleton 布局骨架](../components/layout-skeleton.zh.mdc)
- [Tabs 标签页](../components/tabs.zh.mdc)
- [DropdownMenu 下拉菜单](../components/dropdown-menu.zh.mdc)
- [Popover 弹出层](../components/popover.zh.mdc)
- [Drawer 抽屉](../components/drawer.zh.mdc)
- [StatusBadge 状态徽标](../components/status-badge.zh.mdc)
- [ProgressBar 进度条](../components/progress-bar.zh.mdc)
- [EmptyState 空态引导](../components/empty-state.zh.mdc)
- [Toast 提示](../components/toast.zh.mdc)
- [Tooltip 提示](../components/tooltip.zh.mdc)
- [LoadingOverlay 加载遮罩](../components/loading-overlay.zh.mdc)
- [Spinner 加载](../components/spinner.zh.mdc)
