列表页 List Page
客户列表 / 零件报价共用的 list-page 规范组件。样式由 @rd-element/ui 内置 list-page.css 提供。
页头统计 RdListPageHero
完整 · 统计 + 胶囊切换 + 操作(客户列表)
客户
管理全球客户,跟踪合作关系与业务进展
12客户总数
9活跃客户
4企业客户
$2.6M累计金额
简洁 · 标题 + 操作
订单
查看与管理全部销售订单
<script setup lang="ts">
import { ref } from 'vue'
import { Users, CheckCircle, Building2, TrendingUp, User, Plus, Download } from '@lucide/vue'
import { RdListPageHero, RdListPageScopeTabs } from '@rd-element/ui'
const scopeTab = ref<'mine' | 'team'>('mine')
const scopeTabs = [
{ label: '我的客户', value: 'mine' as const, count: 5, icon: User },
{ label: '团队客户', value: 'team' as const, count: 42, icon: Users },
]
const stats = [
{ key: 'total', label: '客户总数', value: '12', icon: Users, tone: 'primary' as const },
{ key: 'active', label: '活跃客户', value: '9', icon: CheckCircle, tone: 'success' as const },
{ key: 'enterprise', label: '企业客户', value: '4', icon: Building2, tone: 'violet' as const },
{ key: 'value', label: '累计金额', value: '$2.6M', icon: TrendingUp, tone: 'accent' as const },
]
</script>
<template>
<RdListPageHero
title="客户"
subtitle="管理全球客户,跟踪合作关系与业务进展"
:stats="stats"
stats-label="客户指标概览"
>
<template #title-extra>
<RdListPageScopeTabs v-model="scopeTab" :tabs="scopeTabs" size="small" aria-label="客户范围" />
</template>
<template #actions>
<el-button :icon="Download">导出</el-button>
<el-button type="primary" :icon="Plus">新增客户</el-button>
</template>
</RdListPageHero>
<RdListPageHero title="订单" subtitle="查看与管理全部销售订单">
<template #actions>
<el-button :icon="Download">导出</el-button>
<el-button type="primary" :icon="Plus">新建订单</el-button>
</template>
</RdListPageHero>
</template>客群侧栏 RdListPageSidebar
只负责树形数据与选中;面板标题 / 收起由 RdListPageContentRow 提供。
<script setup lang="ts">
import { ref } from 'vue'
import { RdListPageSidebar, type SidebarGroup } from '@rd-element/ui'
const sidebarId = ref('value:strategic')
const groups: SidebarGroup[] = [
{
key: 'value',
label: '客户价值模型',
nodes: [
{ id: 'value:strategic', label: '战略级', count: 4, tone: 'primary' },
{ id: 'value:key', label: '重要级', count: 3, tone: 'violet' },
],
},
]
</script>
<template>
<RdListPageSidebar
v-model="sidebarId"
:groups="groups"
:total-count="12"
total-label="全部客户"
/>
</template>内容行 RdListPageContentRow
左右布局壳:左侧可收起,右侧放 RdListPageDataPanel。merged 时合成一张大卡片。#aside 内放 RdListPageSidebar;编辑等操作放 #aside-actions。
客户列表12 条结果
选中客群后展示表格
演示 ContentRow + DataPanel
<script setup lang="ts">
import { ref } from 'vue'
import { Pencil } from '@lucide/vue'
import {
RdListPageContentRow,
RdListPageSidebar,
RdListPageDataPanel,
RdListPagePanelHeader,
RdListPageStatusTabs,
RdListPageTableEmpty,
type SidebarGroup,
} from '@rd-element/ui'
const sidebarId = ref('value:strategic')
const statusTab = ref('All')
const groups: SidebarGroup[] = [/* … */]
const statusTabs = [
{ label: '全部', value: 'All', count: 48 },
{ label: '待报价', value: 'Pending', count: 12 },
]
</script>
<template>
<RdListPageContentRow
aside-title="客群列表"
:aside-active="!!sidebarId"
merged
>
<template #aside-actions>
<button type="button" class="lp-sidebar__edit-btn" title="编辑">
<Pencil :size="14" />
</button>
</template>
<template #aside>
<RdListPageSidebar
v-model="sidebarId"
:groups="groups"
:total-count="12"
total-label="全部客户"
/>
</template>
<RdListPageDataPanel>
<template #header>
<RdListPagePanelHeader title="客户列表" :count="12" />
<RdListPageStatusTabs v-model="statusTab" :tabs="statusTabs" />
</template>
<RdListPageTableEmpty title="选中客群后展示表格" />
</RdListPageDataPanel>
</RdListPageContentRow>
</template>范围切换 RdListPageScopeTabs
<script setup lang="ts">
import { ref } from 'vue'
import { User, Users } from '@lucide/vue'
import { RdListPageScopeTabs } from '@rd-element/ui'
const scopeTab = ref<'mine' | 'team'>('mine')
const tabs = [
{ label: '我的客户', value: 'mine' as const, count: 5, icon: User },
{ label: '团队客户', value: 'team' as const, count: 42, icon: Users },
]
</script>
<template>
<RdListPageScopeTabs v-model="scopeTab" :tabs="tabs" aria-label="客户范围" />
</template>状态切换 RdListPageStatusTabs
<script setup lang="ts">
import { ref } from 'vue'
import { RdListPageStatusTabs } from '@rd-element/ui'
const statusTab = ref('All')
const tabs = [
{ label: '全部', value: 'All', count: 48 },
{ label: '待报价', value: 'Pending', count: 12 },
{ label: '报价中', value: 'InProgress', count: 6 },
{ label: '已报价', value: 'Quoted', count: 24 },
{ label: '已确认', value: 'Confirmed', count: 0 },
{ label: '已失效', value: 'Expired', count: 2 },
]
</script>
<template>
<RdListPageStatusTabs v-model="statusTab" :tabs="tabs" />
</template>数据面板 RdListPageDataPanel
组合 PanelHeader、FilterBar、FilterChips 与表格空态。
48 条结果
关键词
已选关键词:Pacific状态:活跃
未找到匹配的数据
试试调整关键词
<script setup lang="ts">
import { ref } from 'vue'
import { X } from '@lucide/vue'
import {
RdListPageDataPanel,
RdListPagePanelHeader,
RdListPageFilterBar,
RdListPageFilterChips,
RdListPageStatusTabs,
RdListPageTableEmpty,
RdInputGroup,
toast,
} from '@rd-element/ui'
const statusTab = ref('All')
const statusTabs = [
{ label: '全部', value: 'All', count: 48 },
{ label: '待报价', value: 'Pending', count: 12 },
{ label: '已报价', value: 'Quoted', count: 24 },
]
const filterTags = [
{ key: 'search', label: '关键词:Pacific', remove: () => toast.info('移除标签', '演示交互') },
{ key: 'status', label: '状态:活跃', remove: () => {} },
]
const columnItems = [
{ key: 'company', label: '公司', visible: true, fixed: true },
{ key: 'contact', label: '联系人', visible: true },
{ key: 'country', label: '国家', visible: true },
{ key: 'tier', label: '等级', visible: false },
]
</script>
<template>
<RdListPageDataPanel>
<template #header>
<RdListPagePanelHeader tabs>
<template #left>
<RdListPageStatusTabs v-model="statusTab" :tabs="statusTabs" />
</template>
<template #right>
<span class="data-panel__count">48 条结果</span>
<button type="button" class="text-action-btn"><X :size="13" /> 清除筛选</button>
</template>
</RdListPagePanelHeader>
</template>
<RdListPageFilterBar :column-items="columnItems" :drawer-filter-count="2" @open-drawer="() => {}">
<RdInputGroup>
<template #left>关键词</template>
<el-input placeholder="关键词搜索" clearable />
</RdInputGroup>
</RdListPageFilterBar>
<RdListPageFilterChips :tags="filterTags" />
<RdListPageTableEmpty title="未找到匹配的数据" hint="试试调整关键词" show-action @action="() => {}" />
</RdListPageDataPanel>
</template>全部筛选 RdListPageFilterDrawer
也可从上方「数据面板」中的「全部筛选」按钮打开同一抽屉实例。
<script setup lang="ts">
import { ref } from 'vue'
import { Filter } from '@lucide/vue'
import {
RdInputGroup,
RdListPageFilterDrawer,
toast,
type FilterFieldSettingItem,
} from '@rd-element/ui'
const visible = ref(false)
const tab = ref<'filters' | 'layout'>('filters')
const keyword = ref('')
const status = ref<string[]>([])
const layoutItems = ref<FilterFieldSettingItem[]>([
{ key: 'search', label: '关键词', inlineVisible: true, order: 0, fixed: true },
{ key: 'status', label: '状态', inlineVisible: true, order: 1 },
{ key: 'tier', label: '等级', inlineVisible: true, order: 2 },
{ key: 'region', label: '地区', inlineVisible: false, order: 3 },
])
const layoutCustomized = ref(false)
function openFilters() {
tab.value = 'filters'
visible.value = true
}
</script>
<template>
<el-button type="primary" @click="openFilters">
<Filter :size="14" />
打开全部筛选
</el-button>
<RdListPageFilterDrawer
v-model:visible="visible"
v-model:tab="tab"
:filter-layout-items="layoutItems"
:filter-layout-customized="layoutCustomized"
@apply="() => { visible = false; toast.success('已应用', '筛选条件已更新') }"
@reset="() => { keyword = ''; status = [] }"
>
<template #filters>
<RdInputGroup>
<template #left>关键词</template>
<el-input v-model="keyword" placeholder="公司、联系人、邮箱" clearable />
</RdInputGroup>
<RdInputGroup>
<template #left>状态</template>
<el-select v-model="status" placeholder="全部" multiple collapse-tags clearable>
<el-option label="活跃" value="Active" />
<el-option label="未活跃" value="Inactive" />
</el-select>
</RdInputGroup>
</template>
</RdListPageFilterDrawer>
</template>批量操作栏 RdListPageBulkBar
已选 3 条
<script setup lang="ts">
import { ref } from 'vue'
import { RdListPageBulkBar, toast } from '@rd-element/ui'
const count = ref(3)
</script>
<template>
<el-button size="small" @click="count = count ? 0 : 3">
{{ count ? '隐藏' : '显示' }}
</el-button>
<RdListPageBulkBar
:count="count"
flush
show-cross-page
:cross-page-total="48"
@clear="count = 0"
@toggle-cross-page="toast.info('跨页', '演示切换')"
>
<template #actions>
<button type="button" class="bulk-action-btn">修改状态</button>
<button type="button" class="bulk-action-btn bulk-action-btn--danger">删除</button>
</template>
</RdListPageBulkBar>
</template>说明
- 列设置与筛选项配置详见 配置面板 Settings
- 表格行内编辑、分页等详见 表格增强 Table