Группировка заголовков
Вложенный массив children у колонки объединяет несколько колонок под общим заголовком — шапка становится многоуровневой.
<script setup lang="ts">
import type { NTable } from '@central-design-system/components';
import { CdsTable } from '@central-design-system/components';
const columns: NTable.NColumn.TColumns = [
{ title: 'Имя', dataIndex: 'name', key: 'name', width: 100, fixed: 'left' },
{
title: 'Информация',
children: [
{ title: 'Возраст', dataIndex: 'age', key: 'age', width: 200 },
{
title: 'Адрес',
children: [
{ title: 'Улица', dataIndex: 'street', key: 'street', width: 200 },
{
title: 'Дом',
children: [
{ title: 'Корпус', dataIndex: 'building', key: 'building', width: 100 },
{ title: 'Квартира', dataIndex: 'number', key: 'number', width: 100 }
]
}
]
}
]
},
{
title: 'Компания',
children: [
{ title: 'Адрес компании', dataIndex: 'companyAddress', key: 'companyAddress', width: 200 },
{ title: 'Название компании', dataIndex: 'companyName', key: 'companyName' }
]
},
{ title: 'Пол', dataIndex: 'gender', key: 'gender', width: 80, fixed: 'right' }
];
const data = [...Array(10)].map((_, i) => ({
key: i,
name: 'Иван',
age: i + 1,
street: 'Главная',
building: 'Б',
number: 1004,
companyAddress: 'г. Москва, ул. Ленина',
companyName: 'B2B-Center',
gender: 'Муж'
}));
</script>
<template>
<CdsTable :columns="columns" :data="data" :pagination="false" :scroll="{ x: 'calc(700px + 50%)', y: 240 }" bordered />
</template>Объединение ячеек
Функция колонки customCell возвращает colSpan/rowSpan для конкретной ячейки, а colSpan на самой колонке объединяет ячейки заголовка. Ячейка со значением colSpan: 0 не рендерится.
<script setup lang="ts">
import type { NTable } from '@central-design-system/components';
import { CdsTable } from '@central-design-system/components';
type TDataType = { key: string; name: string; age: number; tel: string; phone: string; address: string };
const columns: NTable.NColumn.TColumns<TDataType> = [
{
title: 'Имя',
dataIndex: 'name',
customCell: (_, index) => ({ colSpan: index! < 4 ? 1 : 5 })
},
{
title: 'Возраст',
dataIndex: 'age',
customCell: (_, index) => {
if (index === 4) return { colSpan: 0 };
}
},
{
title: 'Номер телефона',
colSpan: 2,
dataIndex: 'tel',
customCell: (_, index) => {
if (index === 2) return { rowSpan: 2 };
if (index === 3) return { rowSpan: 0 };
if (index === 4) return { colSpan: 0 };
}
},
{
title: 'Номер домашнего телефона',
colSpan: 0,
dataIndex: 'phone',
customCell: (_, index) => {
if (index === 4) return { colSpan: 0 };
}
},
{
title: 'Адрес',
dataIndex: 'address',
customCell: (_, index) => {
if (index === 4) return { colSpan: 0 };
}
}
];
const data: TDataType[] = [
{
key: '1',
name: 'Иванов Иван',
age: 20,
tel: '79999999999',
phone: '74959999999',
address: 'г. Москва, ул. Ленина д. 1'
},
{
key: '2',
name: 'Иванов Василий',
tel: '79999999999',
phone: '74959999999',
age: 32,
address: 'г. Москва, ул. Ленина д. 2'
},
{
key: '3',
name: 'Иванов Кирилл',
age: 41,
tel: '79999999999',
phone: '74959999999',
address: 'г. Москва, ул. Ленина д. 3'
},
{
key: '4',
name: 'Иванов Александр',
age: 30,
tel: '79999999999',
phone: '74959999999',
address: 'г. Екатеринбург, ул. Ленина д. 4'
},
{
key: '5',
name: 'Иванов Иван',
age: 18,
tel: '79999999999',
phone: '74959999999',
address: 'г. Новосибирск, ул. Ленина д. 5'
}
];
</script>
<template>
<CdsTable :columns="columns" :data="data" :pagination="false" />
</template>Заголовок, тулбар и подвал
Слоты header, toolbar и footer добавляют собственные зоны вокруг таблицы, а проп pagination — встроенную пагинацию со счётчиком записей и выбором размера страницы.
<script setup lang="ts">
import type { ITableProps, NTable } from '@central-design-system/components';
import { CdsButton, CdsTab, CdsTable, CdsTabs, CdsTextInput } from '@central-design-system/components';
import { ref } from 'vue';
type TDataType = { key: number; name: string; money: string; address: string };
const columns: NTable.NColumn.TColumns<TDataType> = [
{ title: 'Название', dataIndex: 'name' },
{ title: 'Адрес', dataIndex: 'address' },
{ title: 'Цена', className: 'column-money', dataIndex: 'money', align: 'right' }
];
const data: TDataType[] = [...Array(100)].map((_, i) => ({
key: i,
name: `Позиция ${i + 1}`,
money: new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' }).format((i + 1) * 10000),
address: `г. Москва, ул. Ленина, д.${i}`
}));
const contentSwitcher = ref(0);
const total = ref(10);
const onChange: ITableProps<TDataType>['onChange'] = (pagination) => {
total.value = pagination.total!;
};
</script>
<template>
<CdsTable
:columns="columns"
:data="data"
:pagination="{ total, counter: true, size: true, position: ['bottomLeft'] }"
@change="onChange"
>
<template #header>
<div class="flex justify-between">
<div>
<h4 class="mb-2">Заголовок таблицы</h4>
<p class="mb-4 text-content-secondary">Описание таблицы в слоте заголовка таблицы</p>
<div class="flex">
<CdsTabs v-model="contentSwitcher">
<CdsTab v-for="i in 5" :key="i">Текст</CdsTab>
</CdsTabs>
</div>
</div>
<div>
<CdsButton variant="soft" color="brand" text="Внешнее действия" />
</div>
</div>
</template>
<template #toolbar>
<div class="flex justify-between">
<div class="flex gap-4">
<CdsTextInput prepend-inner-icon="search" placeholder="Описание поиска" hide-messages class="w-[250px]" />
<CdsButton prepend-icon="adjust" text="Фильтры" variant="soft" color="neutral" />
</div>
<div class="flex gap-2">
<CdsButton variant="soft" color="brand" text="Отменить" />
<CdsButton text="Действие" />
</div>
</div>
</template>
<template #footer>
<div class="flex items-center justify-between">
<h4>Подвал таблицы</h4>
<div class="flex gap-2">
<CdsButton variant="soft" color="brand" text="Отменить" />
<CdsButton text="Действие" />
</div>
</div>
</template>
</CdsTable>
</template>Изменение ширины колонок
Свойство колонки resizable включает перетаскивание границы заголовка. Новую ширину сообщает событие resize-column — сохраните её в описании колонок.
<script setup lang="ts">
import type { NTable } from '@central-design-system/components';
import { CdsTable } from '@central-design-system/components';
import { ref } from 'vue';
type TDataType = { key: string; name: string; price: string; address: string; tags: string };
const columns = ref<NTable.NColumn.TColumns<TDataType>>([
{ title: 'Наименование', dataIndex: 'name', key: 'name', resizable: true, width: 150 },
{
title: 'Цена',
dataIndex: 'price',
key: 'price',
align: 'right',
resizable: true,
width: 100,
minWidth: 100,
maxWidth: 200
},
{ title: 'Адрес', dataIndex: 'address', key: 'address' },
{ title: 'Наличие', key: 'tags', dataIndex: 'tags' }
]);
const data: TDataType[] = [
{
key: '1',
name: 'iPhone 17 Pro Max',
price: '$1500',
address: 'г. Москва, ул. Ленина, д. 1',
tags: 'В наличии'
},
{
key: '2',
name: 'MacBook Air M5',
price: '$2000',
address: 'г. Москва, ул. Ленина, д. 1',
tags: 'В наличии'
},
{
key: '3',
name: 'Apple Vision Pro',
price: '$3500',
address: 'г. Нью-Йорк, ул. Ленина, д. 1',
tags: 'Нет в наличии'
}
];
const handleResizeColumn = (width: number, column: NTable.NColumn.IColumn) => {
column.width = width;
};
</script>
<template>
<CdsTable :columns="columns" :data="data" :pagination="false" @resize-column="handleResizeColumn" />
</template>Декларативное описание колонок
Вместо массива columns колонки можно описать в разметке компонентами CdsTableColumn и CdsTableColumnGroup — удобно, когда заголовкам и ячейкам нужна своя разметка.
<script setup lang="ts">
import { CdsStatus, CdsTable, CdsTableColumn, CdsTableColumnGroup, CdsToggle } from '@central-design-system/components';
type TDataType = {
key: string;
firstName: string;
lastName: string;
age: number;
address: string;
tags: string[];
};
const data: TDataType[] = [
{
key: '1',
firstName: 'Иван',
lastName: 'Иванов',
age: 20,
address: 'г. Москва, ул. Ленина, д. 1',
tags: ['Senior', 'Developer']
},
{
key: '2',
firstName: 'Анатолий',
lastName: 'Анатольев',
age: 42,
address: 'г. Москва, ул. Ленина, д. 2',
tags: ['Junior', 'Developer']
},
{
key: '3',
firstName: 'Игнат',
lastName: 'Игнатьев',
age: 33,
address: 'г. Москва, ул. Ленина, д. 3',
tags: ['Junior', 'Developer']
},
{
key: '4',
firstName: 'Петр',
lastName: 'Петров',
age: 28,
address: 'г. Москва, ул. Ленина, д. 4',
tags: ['Middle', 'Developer']
}
];
</script>
<template>
<CdsTable :data="data" :pagination="false">
<CdsTableColumnGroup>
<template #title>
<span class="text-brand-primary">Сотрудник</span>
</template>
<CdsTableColumn key="firstName" data-index="firstName">
<template #title>
<span class="text-brand-primary">Имя</span>
</template>
</CdsTableColumn>
<CdsTableColumn key="lastName" title="Фамилия" data-index="lastName" />
</CdsTableColumnGroup>
<CdsTableColumn key="age" title="Возраст" data-index="age" />
<CdsTableColumn key="address" title="Адрес" data-index="address" />
<CdsTableColumn key="tags" title="Особенности" data-index="tags">
<template #default="{ text: tags }">
<CdsStatus
v-for="tag in tags"
:key="tag"
:status="tag === 'Junior' ? 'danger' : tag === 'developer' ? 'info' : 'success'"
class="mr-2"
>
{{ tag }}
</CdsStatus>
</template>
</CdsTableColumn>
<CdsTableColumn key="action" title="Действия" data-index="action">
<template #default="{ record }">
<CdsToggle :disabled="!record.tags.includes('Junior')" hide-messages />
</template>
</CdsTableColumn>
</CdsTable>
</template>