Skip to content

v1.4 — 27/03/2026

Thay đổiSectionẢnh hưởng
Đổi label dropdown "Commission tư vấn" → "Hoa hồng tư vấn" (DEC-012)B2 Filter Bar, B7 Copy Text, B9 TooltipFE

UI Spec — Báo cáo doanh số cá nhân

Ref: PRD v1.3 | Date: 2026-03-23


B1) Screen Map

SCRTênRouteMô tả
SCR-00Báo cáo doanh số cá nhân (Hub)/r/reports/employee_daily_commission_groupTab container: 3 tabs
SCR-01Tab: Doanh số theo ngàyTab panel trong SCR-00Filter + pivot table + export (build mới)
SCR-02Popup chi tiết giao dịch ngàyQDialog (trên SCR-01)Drill-down: danh sách giao dịch commission + truy thu
SCR-03Tab: Doanh thu theo đơn hàngTab panel trong SCR-00Import EmployeeRevenueReport component
SCR-04Tab: Tiền tourTab panel trong SCR-00Import TourIncomeReport component

B1.1) SCR-00: Tab Container (Ref: FR-009, DEC-011)

Layout

┌─ Báo cáo doanh số cá nhân ──────────────────────────────────────┐
│                                                                   │
│  [ Doanh số theo ngày ✓ ]  [ Doanh thu theo đơn hàng ]  [ Tiền tour ] │
│                                                                   │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │                                                               │ │
│ │              Nội dung tab đang active                         │ │
│ │                                                               │ │
│ └───────────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘

Tabs

#Tab labelQuery paramComponentLazy load
1Doanh số theo ngày?tab=daily (default)EmployeeDailyCommission (build mới)No (default)
2Doanh thu theo đơn hàng?tab=revenueEmployeeRevenueReport (import hiện có)Yes
3Tiền tour?tab=tourTourIncomeReport (import hiện có)Yes

Route redirect (bookmark safe)

Route cũRedirect →
/r/reports/employee_revenue_report_group/r/reports/employee_daily_commission_group?tab=revenue
/r/reports/tour_income_report_group/r/reports/employee_daily_commission_group?tab=tour

B2) SCR-01: Doanh số theo ngày (Tab default)

Layout

┌─────────────────────────────────────────────────────────────┐
│ [Loại: Commission tư vấn ▼] [◀ 03/2026 ▶] [CN ▼] [CV ▼]  │
│                                              [📥 Tải xuống] │
├─────┬──────────────────┬────────┬────────┬───┬────────┬─────┤
│ Mã  │ Họ tên           │ 01/03  │ 02/03  │...│ 31/03  │Tổng │
├─────┼──────────────────┼────────┼────────┼───┼────────┼─────┤
│DV220│Nguyễn Thị Giang  │3.700.00│4.000.00│   │7.018.00│ xxx │
│DV250│Mai Thùy Dương     │3.331.00│2.600.00│   │7.729.00│ xxx │
│DV250│Nguyễn Thị Uyên   │      0 │      0 │   │      0 │   0 │
│ ... │ ...               │  ...   │  ...   │   │  ...   │ ... │
└─────┴──────────────────┴────────┴────────┴───┴────────┴─────┘

Filter Bar

#ComponentTypeDefaultBehavior
1Loại doanh sốQSelect"Hoa hồng tư vấn"Options: "Hoa hồng tư vấn", "Tiền tour", "Truy thu commission". Switch → re-fetch data. Khi chọn "Truy thu commission" → ẩn filter chức vụ
2ThángMonthPickerWithButtonTháng hiện tạiNút ◀ ▶ prev/next. Format: MM/YYYY
3Chi nhánhBranchSelectTất cảMulti-select. Empty = tất cả
4Chức vụJobPositionSelectTất cảMulti-select. Empty = tất cả
5Tải xuốngQBtn icon downloadClick → export Excel

Pivot Table

CộtWidthAlignFormatSticky
Mã NV100pxLeftTextYes (sticky left)
Họ tên180pxLeftTextYes (sticky left)
01/DD — 31/DD110px eachRightxxx.xxx.xxx (VND)No
Tổng130pxRightxxx.xxx.xxx (VND) boldYes (sticky right)

Đặc tả cột ngày:

  • Số cột = số ngày thực tế trong tháng (28/29/30/31)
  • Header format: DD/MM (VD: 01/03, 02/03, ..., 31/03)
  • Giá trị 0 hiển thị 0 (không để trống)

Cell click (drill-down):

  • Ô số tiền (cột ngày + cột Tổng): cursor pointer, hover highlight
  • Click → mở SCR-02 popup chi tiết
  • Click cột ngày → popup filter theo NV + ngày đó
  • Click cột Tổng → popup filter theo NV + cả tháng

Sort:

  • Mặc định: employee_code ASC
  • Click header cột ngày/tổng → sort DESC/ASC

Scroll:

  • Horizontal scroll cho cột ngày (sticky Mã NV + Họ tên bên trái, Tổng bên phải)
  • Vertical scroll cho danh sách NV

Permission Matrix

RoleXem pageExport
HCNS (được gán report)
BOD
IT Leader/Staff
Roles khác

State Matrix

StateHiển thị
LoadingSkeleton loading trên table area
Empty (không có data)"Không có dữ liệu cho tháng này" centered trong table area
Error (query fail)"Đã xảy ra lỗi. Vui lòng thử lại." + nút Retry
No PermissionRoute guard redirect (không vào được page)

B2.1) SCR-02: Popup chi tiết giao dịch ngày (Ref: FR-008, DEC-010)

Layout

┌──────────────────────────────────────────────────────────────────────────┐
│  Chi tiết doanh số — Nguyễn Thị Giang — 01/03/2026                 [✕] │
├────┬────────────┬────────────┬───────────────────┬───────────┬──────────┤
│ #  │Ngày TT     │Mã đơn hàng│Loại ĐH            │Mã GD      │Nhóm GD  │
├────┼────────────┼────────────┼───────────────────┼───────────┼──────────┤
│ 1  │01/03/2026  │DV01009623  │ĐH dịch vụ        │TT02071583 │🏦 CK NH │
│ 2  │01/03/2026  │DV01009624  │ĐH dịch vụ        │TT02071584 │💵 Tiền mặt│
│ 3  │01/03/2026  │DV01009623  │Truy thu commission│WD02089312 │—        │
└────┴────────────┴────────────┴───────────────────┴───────────┴──────────┘
        ... │Khách hàng          │ Doanh thu TƯ VẤN │
            ├─────────────────────┼──────────────────┤
        ... │NGUYỄN HƯƠNG         │      1.500.000   │
        ... │LÊ THỊ LINH          │      2.200.000   │
        ... │—                    │     -1.000.000   │ ← số âm, màu đỏ

Cột popup

#CộtWidthSource (Commission)Source (Truy thu)
1Ngày thanh toán120pxinvoice.paid_attransaction_request.updated_at
2Mã đơn hàng130pxorder.code (clickable)Mã đơn gốc bị hoàn (transaction_request.order_idorder.code)
3Loại đơn hàng170px"ĐH dịch vụ" / "ĐH mỹ phẩm""Truy thu commission" (text đỏ)
4Mã giao dịch120pxinvoice.codetransaction_request.code (fallback: transaction_request.id)
5Nhóm giao dịch150pxpayment_method + icon
6Khách hàng180pxcustomer.display_name + SĐT + mã KH
7Doanh thu tư vấn150pxamount (dương, align right)-amount (số âm, màu đỏ, align right)

Data source

Frontend gọi 2 query song song, merge kết quả:

  1. search_report_employee (ecommerce DB) — commission orders dương
  2. Hasura query trên transaction + transaction_request (wallet DB) — bút toán truy thu

Lưu ý: Amount trong wallet DB luôn >= 0 (CHECK constraint). Frontend negate giá trị khi render clawback rows.

Hiển thị số âm

Điều kiệnStyle
amount > 0Màu mặc định, align right
amount < 0Màu đỏ, format -xxx.xxx.xxx, align right
Loại ĐH = "Truy thu commission"Text đỏ hoặc badge để phân biệt
Dropdown đang chọnClick ô → popup hiện
Commission tư vấnCommission orders + bút toán truy thu (merge cả 2)
Tiền tourChi tiết tour (chỉ query tour, không merge clawback)
Truy thu commissionChỉ bút toán truy thu (chỉ query wallet)

State

StateHiển thị
LoadingSkeleton loading trong dialog body
Empty"Không có giao dịch" centered
Error"Đã xảy ra lỗi. Vui lòng thử lại." + nút Retry

B3) Export Excel Spec

FieldGiá trị
Format.xlsx
Tên filedoanh-so-nv-{MM-YYYY}_{YYYYMMDDHHmmss}.xlsx
Sheet nameDoanh số NV

Columns

#HeaderWidthFormat
1Mã NV15Text
2Họ tên25Text
3-NDD/MM/YYYY (mỗi ngày)15Number #,##0
N+1Tổng18Number #,##0 bold

Styles

ElementStyle
Header rowBold, background excelHeaderStyle, center align
Data — textLeft align
Data — numberRight align, format #,##0
Tổng columnBold

B7) Copy Text Dictionary

KeyText (VI)Context
page_titleBáo cáo doanh số cá nhânPage header (hub)
tab_dailyDoanh số theo ngàyTab label
tab_revenueDoanh thu theo đơn hàngTab label
tab_tourTiền tourTab label
type_commissionHoa hồng tư vấnDropdown option
type_tourTiền tourDropdown option
type_clawbackTruy thu commissionDropdown option
popup_titleChi tiết doanh số — {name} —Popup header
popup_emptyKhông có giao dịchPopup empty state
clawback_labelTruy thu commissionLoại ĐH trong popup
col_employee_codeMã NVTable header
col_employee_nameHọ tênTable header
col_totalTổngTable header
btn_downloadTải xuốngButton label
empty_stateKhông có dữ liệu cho tháng nàyEmpty table
error_stateĐã xảy ra lỗi. Vui lòng thử lại.Error state
btn_retryThử lạiError retry button

B9) Tooltip Dictionary

ElementTooltip text
Dropdown "Loại"Chọn loại doanh số: Hoa hồng tư vấn (tiền hoa hồng thực nhận từ đơn hàng, không tính thanh toán bằng ví) hoặc Tiền tour (tiền từ thực hiện tour dịch vụ)
Cột TổngTổng doanh số trong tháng = tổng tất cả ngày
Nút Tải xuốngXuất file Excel chứa toàn bộ dữ liệu đang hiển thị
Option "Truy thu commission"Hiển thị số tiền commission bị thu hồi khi đơn hàng hoàn tiền. Ghi nhận theo ngày duyệt hoàn
Ô số tiền (hover)Click để xem chi tiết giao dịch

B10) Edge Cases

#CaseBehavior
1NV không có commission/tour nào trong thángVẫn hiển thị row với tất cả cột = 0 (nếu NV thuộc filter branch/job)
2Tháng 2 nhuận (29 ngày)Cột tự động = 29 ngày
3Filter không có NV nào matchHiển thị empty state
4NV thuộc nhiều department/branchHiển thị 1 row (SQL đã group by user_id)
5Commission amount = 0Hiển thị 0 (vẫn có row)
6Tour money = NULLKhông tính (SQL filter tour_money > 0)
7Export khi table emptyTạo file Excel chỉ có header, không có data rows
8Tháng chưa đến (future)Hiển thị table trống — data chưa có
9Switch loại đang loadingCancel request cũ, fetch request mới
10NV bị soft delete giữa thángKhông hiển thị (SQL filter deleted_at IS NULL)
11Click ô = 0Mở popup rỗng: "Không có giao dịch"
12Click ô truy thu, order_id = NULLCột "Mã đơn hàng" hiện
13transaction_request.code = NULLDùng transaction_request.id (UUID) làm fallback
14Click ô khi dropdown = "Tiền tour"Popup chỉ hiện chi tiết tour, không merge clawback
15Click ô khi dropdown = "Truy thu commission"Popup chỉ hiện bút toán truy thu
16Chọn "Truy thu commission" → filter chức vụẨn/disable filter chức vụ (wallet DB không có department)
17Truy cập route cũ /r/reports/employee_revenue_report_groupRedirect → ?tab=revenue, hiển thị tab "Doanh thu theo đơn hàng"
18Truy cập route cũ /r/reports/tour_income_report_groupRedirect → ?tab=tour, hiển thị tab "Tiền tour"
19URL có ?tab=invalidFallback về tab default "Doanh số theo ngày"
20Switch tab giữ filter stateMỗi tab có filter riêng (không share), giữ state khi switch qua lại