Giao diện
CTable — cột và ô dữ liệu
Cột do trang khai báo; CTable không định nghĩa sẵn cột nào. Cấu hình cột giống hệt a-table, cộng vài quy ước của framework.
Khai báo cột
ts
const columns = [
{ title: 'Mã đơn', dataIndex: 'code', key: 'code', width: 140 },
{ title: 'Khách hàng', dataIndex: 'customer', key: 'customer' },
{ title: 'Giá trị', dataIndex: 'amount', key: 'amount', align: 'right', width: 160, sorter: true },
{ title: 'Trạng thái', dataIndex: 'status', key: 'status', width: 150 },
{ title: '', key: 'actions', width: 56, align: 'center' },
]| Field | Vai trò |
|---|---|
title | Nhãn hiển thị ở header. '' đánh dấu cột tiện ích — không xuất hiện trong drawer Thiết lập và giữ nguyên vị trí |
dataIndex | Đường dẫn tới field trong bản ghi; lồng thì dùng mảng ['owner', 'name'] |
key | Định danh cột — dùng cho #bodyCell và cho thiết lập cột |
width | Cố định bề rộng cột hẹp (mã, ngày, trạng thái, hành động) |
align | right cho số tiền, center cho trạng thái và nút |
sorter | true để cột sắp xếp được — xem Sắp xếp |
fixed | 'left' / 'right' ghim cột khi bảng cuộn ngang |
key hoặc dataIndex là bắt buộc khi dùng thiết lập
Bảng có settings-key (hoặc v-model:settings) mà một cột cấu hình được thiếu cả key lẫn dataIndex thì CTable ném lỗi ngay khi dựng: thiết lập lưu theo vị trí sẽ áp nhầm sang cột khác khi thêm hoặc bớt cột.
Render ô: #bodyCell
vue
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'amount'">
{{ currency.format((record as Order).amount) }} ₫
</template>
<template v-else-if="column.key === 'status'">
<CTag :color="ORDER_STATUS[(record as Order).status].color" dot>
{{ ORDER_STATUS[(record as Order).status].label }}
</CTag>
</template>
</template>record có kiểu unknown nên phải ép kiểu tường minh (as Order) — quy ước của core cấm any.
Nhánh v-if so theo column.key, không so theo column.title: đổi nhãn hiển thị sẽ không làm gãy phần render.
Cột số thứ tự
ts
{
title: 'STT',
key: 'index',
width: 64,
align: 'center',
customRender: ({ index }: { index: number }) => (query.page - 1) * query.pageSize + index + 1,
}Phải cộng theo trang hiện tại — index chỉ là vị trí trong trang, nên trang 2 sẽ lại bắt đầu từ 1. query lấy từ useTable.
Cột hành động
vue
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'actions'">
<CDropdown :trigger="['click']">
<CButton variant="text" size="sm" aria-label="Thao tác">
<template #icon><IconDots :size="16" /></template>
</CButton>
<template #overlay>
<CMenu @click="(info) => onAction(info, record as Order)">
<CMenuItem key="edit">Sửa</CMenuItem>
<CMenuItem key="delete" danger>Xoá</CMenuItem>
</CMenu>
</template>
</CDropdown>
</template>
</template>- Đặt
title: ''cho cột hành động: nó không phải dữ liệu, không nên cho người dùng ẩn hay đổi chỗ. - Một hoặc hai hành động thì đặt nút thẳng ra ngoài; từ ba trở lên mới gom vào menu ⋮.
- Chặn quyền bằng
v-cantrên từng nút — xem Chặn theo quyền. CDropdown,CMenu,CMenuItemlà primitive antdv re-export: phảiimporttừ@tasco/ui.
Định dạng dữ liệu
| Loại | Cách làm |
|---|---|
| Tiền | new Intl.NumberFormat('vi-VN') tạo một lần ngoài template, align: 'right' |
| Ngày giờ | Định dạng ở fetcher hoặc bằng hàm dùng chung; đừng gọi dayjs() trong template mỗi lần render |
| Trạng thái | Hằng số map trạng thái → nhãn + màu, dùng chung cho mọi màn hình |
| Chữ dài | ellipsis: true trên cột, bọc CTooltip nếu cần xem đủ |
Bảng rộng
vue
<CTable :scroll="{ x: 1400 }" :columns="columns" />Bảng nhiều cột thì cho cuộn ngang thay vì ép chữ xuống dòng. Ghim cột định danh và cột hành động:
ts
{ title: 'Mã đơn', dataIndex: 'code', key: 'code', width: 140, fixed: 'left' },
{ title: '', key: 'actions', width: 56, fixed: 'right' },Cột fixed chỉ đổi được thứ tự trong nhóm cố định của nó ở drawer Thiết lập, vì antd yêu cầu các cột ghim nằm liền nhau ở mép bảng.
Liên quan
- Trạng thái bảng — loading, rỗng, dòng xen kẽ.
- Thiết lập bảng — người dùng tự ẩn và đổi thứ tự cột.
CTag,CStatus— hiển thị trạng thái trong ô.