Giao diện
API của layer
Những gì @tasco/nuxt-layer-base thêm vào app Nuxt ngoài component C* và composable: khai báo route, directive, hàm cung cấp qua useNuxtApp(), tiện ích server và các khoá state/cookie layer dùng.
RouteMeta
Khai trong definePageMeta. Middleware auth.global và permission.global đọc các khoá này ở mọi lần điều hướng.
| Khoá | Kiểu | Mặc định | Ý nghĩa |
|---|---|---|---|
auth | boolean | true | false → trang công khai, bỏ qua kiểm tra đăng nhập (khai thêm permission(s) thì vẫn kiểm quyền) |
permission | string | — | Cần một quyền |
permissions | string[] | — | Cần tất cả các quyền; khai cùng permission thì gộp lại |
ts
definePageMeta({ permissions: ['/orders/search', '/orders/export'] })| Tình huống | Kết quả |
|---|---|
Chưa đăng nhập, route không khai auth: false | Chuyển tới /auth/login?redirect=<đường dẫn hiện tại> |
Thiếu một trong các quyền khai ở permission(s) | Ném lỗi 403 Bạn không có quyền truy cập trang này. |
Không có khoá "chỉ cần một trong các quyền" — tự kiểm bằng usePermission().canAny() trong trang. Cách dùng: Chặn theo quyền.
Directive v-can
Đăng ký toàn cục bởi plugin 03.permission.
| Cú pháp | Giá trị | Không đủ quyền thì |
|---|---|---|
v-can="'/orders/create'" | Một URI | Ẩn phần tử (display: none), có quyền trở lại thì hiện lại |
v-can="['/orders/update', '/orders/approve']" | Mảng URI — cần tất cả | Như trên |
v-can:disable="'/orders/delete'" | Một URI hoặc mảng | Giữ phần tử, thêm thuộc tính disabled, class is-disabled, pointer-events: none, opacity: 0.5 |
Directive tính lại khi component cập nhật. Super-role trong NUXT_PUBLIC_AUTH_SUPER_ROLES luôn đủ quyền.
Component của layer
Auto-import, không cần khai báo.
| Component | Việc | Trang |
|---|---|---|
<Can> | Bọc nội dung theo quyền; any để chỉ cần một quyền; slot #fallback khi không đủ quyền | Can và v-can |
<TascoLoginForm> | Form đăng nhập IAM đầy đủ (ứng dụng, tài khoản, OTP) | TascoLoginForm |
useNuxtApp()
$tascoError(error, options?)
Cung cấp bởi plugin 04.error. Chuẩn hoá lỗi bất kỳ thành AppError, gọi xử lý theo loại rồi trả về AppError đó.
ts
const { $tascoError } = useNuxtApp()
try {
await removeOrder(id)
} catch (caught) {
const error = $tascoError(caught, { fallbackMessage: 'Không xoá được đơn hàng.' })
if (error.status === 409) await reload()
}| Tuỳ chọn | Kiểu | Mặc định | Ý nghĩa |
|---|---|---|---|
silent | boolean | false | Chỉ phân loại và gọi xử lý 401, không hiện thông báo |
fallbackMessage | string | 'Đã xảy ra lỗi' | Nội dung khi lỗi không có message |
| Loại lỗi | Xử lý |
|---|---|
| 401 | Chuyển tới /auth/login?redirect=…; đang ở trang đăng nhập thì không chuyển |
| 422 | Không hiện gì — form tự hiện lỗi từng trường |
| 5xx, không có mã (mất mạng, timeout) | notification.error, tiêu đề "Lỗi hệ thống" |
| Còn lại (400, 403, 404…) | message.error |
Cùng mã và nội dung lặp lại trong 3 giây chỉ hiện một lần. Plugin cũng gắn hàm này vào app.config.errorHandler và hook vue:error, nên lỗi không ai bắt vẫn hiện theo cùng quy tắc. Chi tiết: Hiển thị lỗi.
$tascoAuth
AuthProvider do plugin 02.auth cung cấp — useAuth() gọi qua nó. Trang không gọi trực tiếp; thay cách đăng nhập thì cung cấp provider khác bằng plugin cùng tên. Kiểu: AuthProvider.
Auto-import
| Nguồn | Tên |
|---|---|
@tasco/composables | useApi, useAuth, usePermission, useTable, useThemeMode |
@tasco/ui (đăng ký toàn cục qua plugin 01.ui) | 17 component thương hiệu: CAppLayout, CButton, CCard, CChat, CChatMessage, CEmpty, CFilterBar, CForm, CInputCurrency, CInputPercent, CPageHeader, CSideNav, CStatistic, CStatus, CTable, CTag, CTopNav |
Phải import tường minh từ @tasco/ui: useConfirm, useErrorHandler, message, notification, các primitive (CInput, CSelect, CModal…) và mọi kiểu (NavItem, CFormInstance…).
Tiện ích server
Nitro auto-import từ server/utils/ của layer vào route server của dự án.
| Hàm | Ý nghĩa |
|---|---|
getTascoSession(event) | Phiên hiện tại { user, accessToken?, expiresAt? } hoặc null (không có cookie, cookie sai hoặc bị sửa) |
setTascoSession(event, session) | Mã hoá rồi ghi cookie tasco_session |
clearTascoSession(event) | Xoá cookie phiên |
sanitizeRedirect(target, fallback?) | Trả target nếu là đường dẫn nội bộ (một / ở đầu), ngược lại trả fallback (mặc định /) |
ts
// server/api/orders/summary.get.ts
export default defineEventHandler(async (event) => {
const session = getTascoSession(event)
if (!session?.accessToken) {
throw createError({ statusCode: 401, statusMessage: 'Phiên đăng nhập đã hết hạn.' })
}
// gọi backend kèm `Authorization: Bearer ${session.accessToken}`, luôn có timeout
})Các hàm khác trong server/utils/iam.ts (iamLogin, fetchUserInfo, mapIamUser…) cũng được auto-import nhưng là chi tiết cài đặt của route đăng nhập, có thể đổi giữa các bản minor — không gọi từ dự án.
State, cookie và storage
Tên do layer đặt; dự án đọc được nhưng không ghi đè bằng giá trị khác kiểu.
| Tên | Loại | Nội dung |
|---|---|---|
tasco:auth:user | useState | AuthUser | null — người dùng hiện tại |
tasco:layout:collapsed | useState | boolean — sidebar đang thu gọn |
tasco:theme | Cookie (1 năm, SameSite=Lax) | 'light' | 'dark' — chế độ người dùng chọn |
tasco_session | Cookie httpOnly | Phiên đăng nhập đã mã hoá — xem Route BFF |
tasco:table:<settingsKey> | localStorage | Thiết lập cột và sắp xếp mặc định của từng CTable |
Dự án đặt state riêng với tiền tố của dự án, không dùng tasco:.
Trang và layout
| File | Ghi đè bằng |
|---|---|
app/layouts/default.vue | app/layouts/default.vue của dự án |
app/pages/auth/login.vue | app/pages/auth/login.vue của dự án |
app/error.vue — trang lỗi toàn màn hình (404, lỗi không bắt được khi render) | app/error.vue của dự án |
Layout mặc định bọc nội dung trang trong <NuxtErrorBoundary>: lỗi render của một trang hiện CEmpty "Đã xảy ra lỗi…" thay vì làm trắng cả app. Cách ghi đè: Layer cung cấp gì.
Liên quan
- Route BFF — các route server của layer.
- @tasco/composables — chữ ký đầy đủ của composable.
- Kiến trúc nội bộ — thứ tự plugin và middleware.