Giao diện POS (Renderer)
1. Kiểm soát Tài liệu
| Thuộc tính | Giá trị |
|---|---|
| Gói | @nx-app/sale-renderer |
| Phiên bản | 0.0.1-0 |
| Loại | Ứng dụng Web (SPA) |
| Runtime | Tauri WebView / Trình duyệt |
| Framework | React 19 + Vite 7 |
2. Phạm vi & Mục tiêu
2.1. Phạm vi
Giao diện POS là lớp hình ảnh và tương tác của hệ thống Điểm bán hàng. Nó chạy bên trong WebView được cung cấp bởi tiến trình host Tauri (sale-main) và xử lý tất cả các tương tác của người dùng, luồng nghiệp vụ và phản hồi hình ảnh.
2.2. Mục tiêu
- Tối ưu hóa Cảm ứng: Các phần tử giao diện có kích thước phù hợp cho tương tác chạm (mục tiêu tối thiểu 44px).
- Tốc độ: Phản hồi tức thì cho các thao tác giỏ hàng.
- Rõ ràng: Thiết kế độ tương phản cao cho các điều kiện ánh sáng khác nhau.
- Hỗ trợ Ngoại tuyến: Các tính năng cốt lõi hoạt động không cần mạng.
- Cập nhật Thời gian thực: Tích hợp WebSocket cho trạng thái đơn hàng.
3. Ngăn xếp Công nghệ
3.1. Framework Cốt lõi
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| React | ^19.2.0 | Thư viện Thành phần UI |
| React DOM | ^19.2.0 | Kết xuất DOM |
| React Router | ^7.11.0 | Định tuyến phía Client |
| TypeScript | ~6.0.2 | An toàn kiểu dữ liệu |
3.2. Quản lý Trạng thái
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| Redux Toolkit | ^2.11.2 | Quản lý Trạng thái Toàn cục |
| React Redux | ^9.2.0 | Liên kết React-Redux |
| TanStack Query | ^5.90.12 | Trạng thái Server & Caching |
| ra-core | ^5.13.4 | Lõi Framework Admin |
3.3. Thành phần UI
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| radix-ui | ^1.4.3 | Các thành phần cơ sở dễ tiếp cận (gói hợp nhất) |
| Tailwind CSS | ^4.1.18 | Utility-first Styling |
| Lucide React | ^0.562.0 | Thư viện Biểu tượng |
| shadcn | ^3.6.2 | Mẫu Thành phần |
| cmdk | ^1.1.1 | Bảng lệnh |
| vaul | ^1.1.2 | Thành phần Ngăn kéo |
| sonner | ^2.0.7 | Thông báo Toast |
3.4. Tích hợp Tauri
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| @tauri-apps/api | ^2.9.1 | Giao tiếp IPC |
| @tauri-apps/plugin-os | ^2.3.2 | Thông tin Hệ điều hành |
| @skipperndt/plugin-machine-uid | ^0.1.3 | Nhận dạng Thiết bị |
3.5. Biểu mẫu
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| React Hook Form | ^7.69.0 | Quản lý Trạng thái Biểu mẫu |
| @hookform/resolvers | ^5.2.2 | Tích hợp resolver schema |
3.6. Trực quan hóa Dữ liệu
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| Recharts | 2.15.4 | Biểu đồ & Đồ thị |
| react-qr-code | ^2.0.18 | Tạo Mã QR |
| react-day-picker | ^9.13.0 | Chọn ngày |
3.7. Giao tiếp Thời gian thực
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| socket.io-client | ^4.8.3 | Giao tiếp WebSocket |
| RxJS | ^7.8.2 | Reactive Streams |
3.8. Bố cục & Tương tác
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| react-grid-layout | ^2.2.2 | Bố cục Dashboard |
| react-resizable | ^3.1.3 | Bảng có thể thay đổi kích thước |
| react-virtuoso | ^4.17.0 | Danh sách ảo hóa |
| @tanstack/react-virtual | ^3.13.13 | Cuộn ảo |
3.9. Build & Phát triển
| Công nghệ | Phiên bản | Mục đích |
|---|---|---|
| Vite | ^7.2.4 | Công cụ Build |
| @vitejs/plugin-react | ^5.1.1 | Tích hợp React |
| lightningcss | ^1.30.2 | Xử lý CSS |
| ESLint | ^9.39.1 | Kiểm tra lỗi mã nguồn |
| Prettier | ^3.8.1 | Định dạng mã nguồn |
4. Kiến trúc
4.1. Các lớp Ứng dụng
4.2. Giao tiếp IPC
Renderer giao tiếp với Tauri backend thông qua một dịch vụ IPC tùy chỉnh:
export class IpcRendererService {
async invoke<TPayload, TResponse>(opts: {
command: string;
payload: TPayload;
}): Promise<TResponse> {
const res = await invoke(command, { payload });
return { data: res } as TResponse;
}
}4.3. Mẫu Data Provider
Sử dụng TauriIpcDataProvider tùy chỉnh mở rộng mẫu REST provider:
export class TauriIpcDataProvider extends DefaultRestDataProvider {
override send<TResponse>(opts: {
resource: string;
params: ISendParams;
}): Promise<ISendResponse<TResponse>> {
return ipcService.invoke({
command: resource,
payload: params,
});
}
}5. Cấu trúc Dự án
apps/sale-renderer/
├── src/
│ ├── application/ # DI Container & Providers
│ │ ├── decorators/ # Decorator tùy chỉnh
│ │ ├── providers/ # Auth & IPC Providers
│ │ │ ├── auth.provider.ts # Provider xác thực
│ │ │ └── ipc-data.provider.ts # Tauri IPC data provider
│ │ └── services/ # Dịch vụ API
│ │ ├── apis/ # Domain API clients (commerce / finance / identity / invoice / payment / sale)
│ │ ├── environment.service.ts
│ │ └── ipc.service.ts # Tauri IPC wrapper
│ ├── components/ # Thành phần UI tái sử dụng
│ │ └── ui/ # Thành phần shadcn/ui
│ ├── constants/ # Hằng số Ứng dụng
│ ├── helpers/ # Các hàm Tiện ích
│ ├── hooks/ # React Hooks tùy chỉnh
│ ├── interfaces/ # Giao diện TypeScript
│ ├── layout/ # Thành phần Bố cục
│ ├── libs/ # Cấu hình Thư viện ngoài
│ ├── redux/ # Redux Store
│ │ └── slices/ # Redux Slices (16 slices)
│ ├── screens/ # Thành phần Màn hình (14 modules)
│ └── socket/ # Tích hợp WebSocket
│ ├── client/ # Socket client
│ └── server/ # Socket server handlers
├── scripts/ # Script Build
└── public/ # Tài sản Tĩnh6. Màn hình & Định tuyến
6.1. Module Màn hình
Các route được khai báo trong App.tsx (công khai), screens/authenticated và screens/restaurant (lồng nhau). Các thư mục trong src/screens:
| Module | Route | Mô tả |
|---|---|---|
| home | / | Trang chủ / dashboard của merchant |
| sale-v2 | /sale/:saleOrderId | Giao diện POS chính (danh mục FnB + giỏ hàng) |
| order-checkout | /order-checkout/:id | Checkout đơn hàng & các bước thanh toán |
| invoice | /invoice, /invoice/:id/show | Danh sách & chi tiết hóa đơn |
| kitchen | /kitchen | Màn hình bếp (KDS) |
| restaurant-table | /restaurant/* | Sơ đồ mặt bằng / bàn & đặt chỗ |
| settings | /setting | Cài đặt ứng dụng |
| customer | /customer | Màn hình hướng khách hàng (màn hình phụ) |
| sign-in | /login | Xác thực |
| privacy-policy | /privacy-policy | Chính sách quyền riêng tư |
| terms-and-conditions | /terms-and-conditions | Điều khoản & điều kiện |
| errors | /authentication-error, /access-denied, * | Trang 401 / 403 / 404 / 500 / 503 / crash |
| authenticated | (wrapper) | Cây route được bảo vệ xác thực |
| restaurant | (wrapper) | Wrapper route nhà hàng (tải sơ đồ mặt bằng) |
6.2. Thành phần Màn hình Bán hàng
Màn hình bán hàng (screens/sale-v2) là giao diện chính với các thành phần con phức tạp:
screens/sale-v2/
├── Sale.screen.tsx # Màn hình bán hàng chính
├── SaleMain.tsx # Bố cục bán hàng
├── SaleOrderAlertDialog.tsx # Hộp thoại cảnh báo đơn hàng
├── index.tsx
├── fnb/ # Danh mục Thực phẩm & Đồ uống
│ ├── category/ # Điều hướng danh mục
│ ├── product/ # Danh sách sản phẩm
│ ├── product-bundle/ # Lựa chọn combo
│ └── product-variant/ # Lựa chọn biến thể sản phẩm
├── cart/ # Giỏ hàng mua sắm
│ ├── context/ # Context giỏ hàng
│ ├── items/ # Danh sách mục giỏ hàng
│ │ ├── header/ # Tiêu đề giỏ hàng
│ │ └── item/ # Mục riêng lẻ
│ ├── detail/ # Xem chi tiết giỏ hàng
│ │ ├── customer/ # Gắn khách hàng
│ │ └── sale-channel/ # Chọn kênh bán hàng
│ └── summary/ # Tóm tắt giỏ hàng
│ ├── details/ # Chi tiết giá
│ └── actions/ # Các hành động giỏ hàng
└── shift/ # Điều khiển ca / phiên POS7. Quản lý Trạng thái
7.1. Cấu hình Redux Store
const appReducer = combineReducers({
temporary: temporaryReducer,
common: commonReducer,
userProfile: userProfileReducer,
order: orderReducer,
sale: saleReducer,
product: productReducer,
payment: paymentReducer,
invoice: invoiceReducer,
setting: settingReducer,
kitchen: kitchenReducer,
broadcast: broadcastReducer,
session: sessionReducer,
configuration: configurationReducer,
restaurant: restaurantReducer,
shift: shiftReducer,
financeAccount: financeAccountReducer,
});7.2. Redux Slices
| Slice | Mục đích |
|---|---|
| order | Đơn hàng đang mở (giỏ hàng): các mục, số lượng & tổng giá |
| sale | Trạng thái không gian bán hàng |
| product | Trạng thái duyệt danh mục sản phẩm |
| payment | Trạng thái luồng thanh toán |
| invoice | Trạng thái danh sách / chi tiết hóa đơn |
| setting | Trạng thái cài đặt ứng dụng |
| kitchen | Trạng thái màn hình bếp (KDS) |
| broadcast | Trạng thái kênh broadcast / signal thời gian thực |
| session | Trạng thái phiên POS |
| configuration | Trạng thái cấu hình merchant / commerce |
| restaurant | Trạng thái sơ đồ mặt bằng & bàn nhà hàng |
| shift | Trạng thái điều khiển ca |
| financeAccount | Trạng thái tài khoản tài chính (phương thức thanh toán) |
| userProfile | Hồ sơ người dùng đã xác thực |
| common | Trạng thái UI chung |
| temporary | Dữ liệu UI tạm thời / thoáng qua |
7.3. Cấu trúc Trạng thái Đơn hàng
Giỏ hàng được hậu thuẫn bởi slice order (IOrderState). Các mục được lưu theo khóa là bản ghi sale-order-item, và tổng giá được tính lại sau mỗi lần thay đổi:
interface IOrderState {
saleOrderCount: number;
saleOrderItemCount: number;
saleOrderItems: { [saleOrderItemId: string]: ISaleOrderItem };
itemToSaleOrderItemsMap: { [itemId: string]: string };
lastModifySaleOrderItem: string;
// Tính toán giá
totalPrice: number;
totalPurchaseVoucherPrice: number;
totalDiscountVoucherPrice: number;
totalTaxPrice: number;
totalPaymentPrice: number;
taxPercentage: string;
paymentMethod: string;
financeAccount: IFinanceAccount | null;
}7.4. Hành động Đơn hàng
| Hành động | Mô tả |
|---|---|
resetOrder | Đặt lại về trạng thái ban đầu |
resetOrderCheckout | Xóa các mục đơn hàng & thông tin checkout |
resetSaleOrderItems | Chỉ xóa các mục sale-order |
loadSaleOrderItems | Tải các mục từ backend |
addSaleOrderItem | Thêm mục vào đơn hàng |
removeSaleOrderItem | Xóa mục khỏi đơn hàng |
updateQuantitySaleOrderItem | Cập nhật số lượng mục |
updateTaxPercentage | Đặt thuế suất |
8. Dịch vụ API
8.1. API Client IPC
Tất cả các API client giao tiếp qua Tauri IPC và kế thừa BaseCrudApiService (CRUD cùng các lệnh đặc thù theo domain). Chúng nằm dưới application/services/apis, được tổ chức theo domain backend:
| Domain | API Clients |
|---|---|
| identity | AuthApi, PinAuthApi, UserApi |
| commerce | CategoryApi, ProductApi, ProductVariantApi, MerchantApi, OrganizerApi, SaleChannelApi, ConfigurationApi, DeviceApi, ReceiptTemplateApi, SettingApi, AssetApi, AllocationLayoutApi, AllocationUnitApi, AllocationZoneApi |
| sale | SaleOrderApi, SaleOrderItemApi, SaleCustomerApi, ReservationApi, AllocationUsageApi, KitchenTicketApi, KitchenTicketItemApi, SalesReportApi, ShiftApi |
| finance | FinanceAccountApi, FinanceAssetApi, FinanceCategoryApi, FinanceWalletApi |
| payment | PaymentApi, PaymentAttemptApi |
| invoice | InvoiceApi |
Các thao tác thêm/xóa/làm trống giỏ hàng và checkout được phục vụ bởi SaleOrderApi / SaleOrderItemApi (ánh xạ tới các lệnh sale_order / sale_order_item của host), không phải một client giỏ hàng riêng.
9. Tích hợp WebSocket
9.1. Kiến trúc Socket
socket/
├── client/ # Client-side socket
│ ├── index.ts # Socket client exports
│ ├── socket-connection-manager.ts # Quản lý kết nối
│ └── socket-subscription-manager.ts # Xử lý đăng ký
├── server/ # Server message handlers
│ ├── base/ # Các lớp socket cơ sở
│ │ ├── base-socket.ts # Lớp socket cơ sở
│ │ └── base-socket-subscription-manager.ts
│ ├── messages/ # Trình xử lý tin nhắn
│ │ └── market-data-socket-message-handler.ts
│ └── order-socket.service.ts # Dịch vụ socket đơn hàng
├── constants.ts # Hằng số socket
├── helper.ts # Tiện ích socket
├── types.ts # Kiểu dữ liệu socket
└── index.ts # Main exports9.2. Tính năng Socket
- Cập nhật Trạng thái Đơn hàng: Thay đổi trạng thái đơn hàng thời gian thực
- Dữ liệu Thị trường: Cập nhật giá trực tiếp
- Quản lý Kết nối: Tự động kết nối lại khi mất kết nối
- Hệ thống Đăng ký: Đăng ký/hủy đăng ký các kênh
10. Thành phần Radix UI
10.1. Gói Hợp nhất
Các primitive Radix được dùng qua gói hợp nhất duy nhất radix-ui (^1.4.3) thay vì các gói @radix-ui/react-* riêng lẻ. Mỗi primitive được import từ một named export, ví dụ:
import { Dialog, DropdownMenu, Tooltip } from 'radix-ui';Các thành phần shadcn/ui trong src/components/ui bọc các primitive này (Accordion, Alert Dialog, Avatar, Checkbox, Collapsible, Context Menu, Dialog, Dropdown Menu, Label, Popover, Radio Group, Scroll Area, Select, Separator, Slot, Switch, Tabs, Tooltip, và nhiều hơn nữa).
11. Hệ thống Giỏ hàng
11.1. Tính năng Giỏ hàng
- Gộp mục: Nhóm các mục giống hệt nhau theo biến thể
- Quản lý Số lượng: Tăng/giảm với xác thực
- Tính toán Giá: Tổng phụ thời gian thực, thuế, chiết khấu
- Phương thức Thanh toán: Hỗ trợ Tiền mặt, QR, Thẻ
- Xử lý Thuế: Phần trăm thuế có thể cấu hình
11.2. Logic Tính toán Giá
// Tính tổng
totalPrice = items.reduce((sum, item) =>
sum + item.unitPrice * item.quantity, 0);
// Áp dụng chiết khấu và thuế
const taxableAmount = Math.max(0, totalPrice - discount);
totalTaxPrice = Math.round(taxableAmount * (taxRate / 100));
totalPaymentPrice = totalPrice
- totalDiscountVoucherPrice
- totalPurchaseVoucherPrice
+ totalTaxPrice;12. Luồng Thanh toán (Checkout Flow)
12.1. Sơ đồ Luồng
12.2. Các bước Thanh toán
- Xem lại Giỏ hàng: Xác minh cuối cùng các mục
- Liên kết Khách hàng: Liên kết khách hàng tùy chọn
- Lựa chọn Thanh toán: Chọn Tiền mặt, QR, hoặc Thẻ
- Thực thi Giao dịch: Xử lý qua Tauri IPC
- Tạo Biên lai: Định dạng cho máy in
- Hoàn tất Đơn hàng: Xóa giỏ hàng và cập nhật trạng thái
13. Điểm Tích hợp
13.1. Thượng nguồn (Tauri Backend)
- Lệnh IPC: Gọi các hàm Rust qua
@tauri-apps/api - Sự kiện: Lắng nghe
init_ready,init_error,migration_error - API Cửa sổ: Quản lý cửa sổ, màn hình ngoài
13.2. Ngang hàng (Các gói Dùng chung)
- @nx-app/core: Tiện ích và locales dùng chung
- @minimaltech/ra-core-infra: Cơ sở hạ tầng dịch vụ cơ bản
- @venizia/ignis-inversion: IoC container
13.3. Hạ nguồn (Backend API)
- WebSocket: Cập nhật đơn hàng thời gian thực
- Telemetry: Ghi log lỗi và phân tích
14. Build & Scripts
14.1. Các Script có sẵn
| Script | Lệnh | Mục đích |
|---|---|---|
dev | vite --mode dev | Development server |
build | sh ./scripts/build.sh | Build sản xuất |
build:develop | sh ./scripts/rebuild.sh development | Build phát triển |
build:production | sh ./scripts/rebuild.sh production | Build sản xuất |
preview | vite preview | Xem trước build |
lint | sh ./scripts/lint.sh | Kiểm tra ESLint |
prettier | prettier '**/*.{js,ts,jsx,tsx}' --write | Định dạng mã |
Dev server chạy trên cổng 3002 (strictPort, từ vite.config.ts), được tiến trình host Tauri tải qua devUrl: http://localhost:3002/.
14.2. Đầu ra Build
Bản build được tiêu thụ bởi tiến trình host Tauri:
- Thư mục đầu ra:
dist/ - Được phục vụ bởi plugin localhost của Tauri
- Được nhúng trong ứng dụng desktop/mobile
15. Thống kê Mã nguồn
| Chỉ số | Số lượng |
|---|---|
| Module Màn hình | 14 |
| Redux Slices | 16 |
| API Clients | các domain commerce / finance / identity / invoice / payment / sale |
| Radix UI | gói hợp nhất radix-ui |
| Trình xử lý Socket | 5+ |
| Custom Hooks | 10+ |