Skip to content

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' },
]
FieldVai trò
titleNhã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
widthCố định bề rộng cột hẹp (mã, ngày, trạng thái, hành động)
alignright cho số tiền, center cho trạng thái và nút
sortertrue để 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-can trên từng nút — xem Chặn theo quyền.
  • CDropdown, CMenu, CMenuItem là primitive antdv re-export: phải import từ @tasco/ui.

Định dạng dữ liệu

LoạiCách làm
Tiềnnew 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áiHằng số map trạng thái → nhãn + màu, dùng chung cho mọi màn hình
Chữ dàiellipsis: 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