Bỏ qua

Page Design: Bản đồ Hiện trạng (Matrix View)

Follows MASTER.md — uses Domain-Specific Pattern "Bản đồ hiện trạng (Matrix View)". Applies to: SCR-MAP-10 Route: /[locale]/current-state-map Users: Manager (edit mapping), Data Owner (review + confirm/dispute), Approver (view + approve)


Layout

+-------------------------------------------------------------------+
| "Bản đồ hiện trạng (Phụ lục C)"                                  |
| "Phân tích sự lưu trữ chồng chéo..."    [AI Matched badge] [▼]  |
+-------------------------------------------------------------------+
| [Filter: Domain ▼] [Filter: Status ▼]   [Search DE...]           |
+-------------------------------------------------------------------+
| Matrix Table (horizontally scrollable)                             |
| ┌──────────┬────────┬────────┬────────┬────────┬─────────────┐   |
| │ Trường DL│ Công an│ Sở TC  │Cục Thuế│ BHXH   │ Ghi chú     │   |
| ├──────────┼────────┼────────┼────────┼────────┼─────────────┤   |
| │ Số CCCD  │  ●     │  ○     │        │  ●     │ chồng chéo  │   |
| │ Họ và tên│  ●     │  ●     │  ●     │  ●     │ định danh   │   |
| │ Số BHYT  │        │        │        │  ●     │ BHXH+Y tế   │   |
| └──────────┴────────┴────────┴────────┴────────┴─────────────┘   |
+-------------------------------------------------------------------+
| [Data Owner role: Confirmation Alert Bar]                          |
+-------------------------------------------------------------------+
  • Critical: Horizontal scroll with sticky first column
  • overflow-x-auto on table container
  • First column sticky left-0 z-10
  • Content area: no max-w-6xl — matrix needs full width

Components

flex justify-between items-end mb-6
  div
    h1.text-2xl.font-bold.text-foreground
    p.text-sm.text-muted-foreground.font-medium.italic
  div.flex.gap-2
    /* AI Matched badge */
    Badge.bg-blue-100.text-blue-700.border-blue-200
    .text-[10px].font-black.uppercase  "AI Matched"
    /* Export button (optional) */
    Button(variant="outline", size="sm")  Download icon

Filter Bar

flex items-center gap-4 mb-6
  /* Domain filter — shadcn Select */
  Select.w-48  placeholder="Tất cả Domain"
  /* Status filter */
  Select.w-48  placeholder="Tất cả trạng thái"
  /* Search */
  div.relative.flex-1
    Search.absolute.left-3.top-1/2.-translate-y-1/2.h-4.w-4.text-muted-foreground
    Input.pl-9.rounded-2xl  placeholder="Tìm Data Element..."

Matrix Table

/* Outer container — rounded, scrollable */
bg-card rounded-3xl border border-border overflow-hidden shadow-sm overflow-x-auto

/* Table */
w-full text-xs text-left border-collapse

/* Header row */
bg-muted border-b border-border
  /* First column header — sticky */
  th.px-6.py-5.sticky.left-0.bg-muted.z-10.w-48
  .border-r.border-border.font-black.text-muted-foreground.uppercase
    "Trường dữ liệu"
  /* Unit column headers */
  th.px-2.py-5.text-center.border-r.border-border.min-w-[80px]
  .font-bold.text-muted-foreground
    /* Unit name — truncated */
  /* Last column: Ghi chú */
  th.px-6.py-5.font-bold.text-muted-foreground.italic.min-w-[200px]
    "Ghi chú hiện trạng"

Matrix Cell — Dot Indicators

/* Cell container */
p-2 border-r border-border text-center

/* Dot states — per MASTER.md Domain-Specific Pattern */
/* DATABASE */
div.w-4.h-4.bg-primary.rounded-[4px].mx-auto.shadow-inner

/* DATABASE_OVERLAP */
div.w-4.h-4.bg-primary/30.rounded-[4px].mx-auto

/* FRAGMENTED */
div.w-4.h-4.bg-warning.rounded-[4px].mx-auto

/* READY */
div.w-4.h-4.bg-success.rounded-[4px].mx-auto

/* EMPTY */
/* no dot, empty cell */

/* DISPUTED */
div.w-4.h-4.bg-destructive.rounded-[4px].mx-auto
/* Cell background: bg-red-50 dark:bg-red-950 */

/* CONFIRMED */
div.w-4.h-4.bg-success.rounded-[4px].mx-auto
/* Cell background: bg-green-50 dark:bg-green-950 */

/* REJECTED */
/* no dot, cell bg-muted, strikethrough on row text */

Matrix Cell — Interaction

/* Clickable cell (Manager) */
cursor-pointer hover:bg-accent/50 transition-colors
/* Click → open SCR-MAP-11 popup (edit mapping) */

/* Data Owner cell (own unit column only) */
cursor-pointer hover:bg-accent/50
/* Click → show context menu: "Xác nhận" / "Đánh dấu tranh chấp" */

/* Approver cell */
cursor-default /* view only */

First Column (Data Element name)

px-6 py-4 sticky left-0 bg-card z-10 border-r border-border
font-bold text-foreground
/* On hover: bg-accent/50 */
/* Transition between card bg and hover */

Notes Column (last)

px-6 py-4 text-muted-foreground italic text-xs

Legend Bar (below table)

flex items-center gap-6 px-6 py-3 bg-muted/30 border-t border-border text-xs

  /* Each legend item */
  flex items-center gap-2
    div.w-3.h-3.rounded-sm  /* colored dot */
    span.text-muted-foreground.font-medium  /* label */

/* Items: ● Lưu trữ | ○ Chồng chéo | ● Phân mảnh | ● Sẵn sàng | ● Tranh chấp | ● Xác nhận */

Data Owner: Dedicated Review Mode (UXI-05 — CREATIVE REDESIGN)

Problem with old mockup: Data Owner forced to navigate a full matrix (all DEs × all units) just to confirm their own unit's 15 fields. Too complex, too many clicks.

New approach: When role = Data Owner, SCR-MAP-10 switches to a card-based review list showing ONLY their unit's mapped fields, with inline confirm/reject per item.

+-----------------------------------------------------------+
| "Xác nhận Hiện trạng — Sở Y tế"                           |
| Deadline: 05/04/2026 (còn 7 ngày)                         |
| ████████████████░░░░░░░░ 53% (8/15 đã xác nhận)           |
+-----------------------------------------------------------+
| [Tab: Chờ xác nhận (7)] [Tab: Đã xác nhận (8)] [Tất cả]  |
+-----------------------------------------------------------+
|                                                           |
| ┌─ Field Card ────────────────────────────────────────┐   |
| │ ho_ten → Họ và tên (DE002-DM1.1)    Score: 0.95    │   |
| │ Nguồn: AI+Rule | Bảng: nhan_vien | Kiểu: VARCHAR  │   |
| │                                                     │   |
| │    [✅ Xác nhận đồng ý]  [🚩 Tranh chấp]           │   |
| └─────────────────────────────────────────────────────┘   |
|                                                           |
| ┌─ Field Card ────────────────────────────────────────┐   |
| │ ma_bhyt → Số BHYT (DE005-DM1.2)     Score: 0.72    │   |
| │ Nguồn: AI | Bảng: benh_nhan | Kiểu: VARCHAR        │   |
| │ ⚠️ "Đơn vị chỉ lưu bản sao, không phải nguồn gốc" │   |
| │                                                     │   |
| │    [✅ Xác nhận đồng ý]  [🚩 Tranh chấp]           │   |
| └─────────────────────────────────────────────────────┘   |
|                                                           |
+-----------------------------------------------------------+
| Sticky bottom bar:                                        |
| [✅ Xác nhận tất cả còn lại (7)]    [Xem dạng ma trận]  |
+-----------------------------------------------------------+
/* Progress header */
bg-card rounded-2xl border border-border p-5 mb-6
  div.flex.items-center.justify-between.mb-3
    h2.text-xl.font-bold  "Xác nhận Hiện trạng — [Unit name]"
    Badge  /* deadline with urgency color */
  /* Progress bar */
  div.space-y-1
    div.flex.justify-between.text-sm.font-semibold
      span  "8/15 đã xác nhận"
      span.text-primary  "53%"
    div.h-3.bg-muted.rounded-full.overflow-hidden
      div.h-full.bg-primary.rounded-full

/* Field review card */
bg-card border border-border rounded-xl p-4 space-y-3
hover:border-primary/20 transition-all

  /* Row 1: mapping info */
  flex items-center justify-between
    div.flex.items-center.gap-2
      span.font-mono.font-bold.text-sm  /* source field */
      ArrowRight.h-4.w-4.text-muted-foreground
      span.font-semibold  /* DE name */
      Badge.font-mono.text-[10px]  /* DE code */
    /* Score */
    div.flex.items-center.gap-2
      div.h-2.w-10.bg-muted.rounded-full
        div.h-full.rounded-full  /* colored by score */
      span.font-mono.text-xs.font-bold

  /* Row 2: metadata */
  div.flex.gap-4.text-xs.text-muted-foreground
    span  "Nguồn: AI+Rule"
    span  "Bảng: nhan_vien"
    span  "Kiểu: VARCHAR"

  /* Row 3: optional warning/note */
  /* If Data Owner previously commented */

  /* Row 4: actions */
  div.flex.items-center.gap-3.pt-2.border-t.border-border
    Button(variant="outline", size="sm").text-success.border-success.hover:bg-success.hover:text-white
      Check.h-4.w-4.mr-1  "Xác nhận đồng ý"
    Button(variant="outline", size="sm").text-destructive.border-destructive.hover:bg-destructive.hover:text-white
      Flag.h-4.w-4.mr-1  "Tranh chấp"
      /* Click → open SCR-MAP-40 popup */

/* Batch action bar (sticky bottom) */
sticky bottom-0 bg-card/95 backdrop-blur-sm border-t border-border p-4
flex items-center justify-between
  Button(variant="default")
    CheckCheck.h-4.w-4.mr-2  "Xác nhận tất cả còn lại (7)"
  Button(variant="ghost")
    Grid3x3.h-4.w-4.mr-2  "Xem dạng ma trận"
    /* Switches to matrix view if Data Owner prefers */

Why better than mockup matrix approach:

  • Focused: Data Owner sees ONLY their fields, not the entire city's matrix
  • Deadline visible: Progress bar + countdown creates urgency without stress
  • 1-click confirm: Inline button per field, no popup
  • Batch confirm: "Xác nhận tất cả" for efficiency
  • Still accessible: "Xem dạng ma trận" toggle for those who want the old view

Data Owner: Confirmation Popup (GAP-07)

/* AlertDialog — triggered by "Xác nhận tất cả" batch action */
AlertDialog
  title: "Xác nhận hiện trạng đơn vị?"
  description: "Bạn xác nhận đồng ý với 7 kết quả matching còn lại.
               Sau khi xác nhận, không thể thay đổi trực tiếp
               (cần đánh dấu tranh chấp nếu phát hiện sai sót)."
  cancel: "Quay lại"
  action: Button(variant="default")  "Xác nhận đồng ý"

Data Owner: Rejection Comment Popup (GAP-07)

/* Dialog — triggered by "Từ chối" action on individual field */
Dialog.max-w-lg
  /* Header */
  h2  "Góp ý chỉnh sửa"
  p  "[field name] → [DE name]"

  /* Body */
  Label  "Nội dung góp ý *"
  Textarea.min-h-[100px]  placeholder="Mô tả lý do không đồng ý..."
  p.text-xs.text-muted-foreground  "Góp ý sẽ được gửi về Manager để điều chỉnh"

  /* Footer */
  Button(variant="outline")  "Hủy"
  Button(variant="default")  "Gửi góp ý"

/* Note: This is different from DISPUTED (which goes to Approver).
   Regular rejection goes back to Manager for adjustment. */

Approver: Readiness Panel (GAP-10)

/* Shown at top of SCR-MAP-10 when role = Approver */
/* Replaces simple DISPUTED badge with a full readiness dashboard */
bg-card rounded-2xl border border-border p-5 mb-6

  h3.font-bold.text-lg.mb-4  "Trạng thái phê duyệt Bảng C"

  div.grid.grid-cols-3.gap-4
    /* Confirmed units */
    div.text-center.p-3.bg-success/10.rounded-xl
      p.text-2xl.font-black.text-success  "18/24"
      p.text-xs.font-semibold.text-success  "Sở đã xác nhận (75%)"

    /* DISPUTED */
    div.text-center.p-3.bg-destructive/10.rounded-xl.cursor-pointer
    .hover:ring-2.hover:ring-destructive
      p.text-2xl.font-black.text-destructive  "3"
      p.text-xs.font-semibold.text-destructive  "Ô DISPUTED"
      /* Click → SCR-MAP-41 */

    /* Readiness */
    div.text-center.p-3.rounded-xl
      /* If both guards pass: bg-success/10 */
      /* If not: bg-warning/10 */
      p.text-2xl.font-black  "⏳"
      p.text-xs.font-semibold  "Chưa đủ điều kiện"
      /* or ✅ "Sẵn sàng phê duyệt" */

  /* CTA */
  div.mt-4.flex.justify-end
    Button(variant="default", disabled={!ready})
      Shield.h-4.w-4.mr-2  "Phê duyệt Bảng C"
      /* Opens SCR-MAP-43 */

Data & Business Rules

Rule Detail
Default sort Data Elements by Domain code ASC, then DE code ASC
Default filter None (show all)
Pagination No pagination — virtual scroll for large datasets
Cell click (Manager) Opens SCR-MAP-11 popup to edit mapping
Cell click (Data Owner) Context menu: Confirm / Dispute (own unit only)
Color coding 8 states per MASTER.md domain-specific pattern
AI badge Shown on cells where match_method = AUTO_AI
Sticky column First column always visible during horizontal scroll

Behaviors

State Trigger Display
Loading Page init Skeleton matrix (header + 5 rows)
Empty No mapping data Empty state: "Chưa có dữ liệu matching. Hãy chạy Discovery trước."
Default Data loaded Matrix with dots + colors
Filter active Select domain/status Matrix filters, URL params updated
Cell hover Mouse over cell Tooltip: "DE name + Unit name + status"
Cell click (Manager) Click cell Open SCR-MAP-11 popup
Confirm (Data Owner) Click "Xác nhận Đồng ý" Toast success, cells turn green
Dispute (Data Owner) Click "Đánh dấu tranh chấp" Open SCR-MAP-40 popup
Approve (Approver) Click DISPUTED badge Navigate to SCR-MAP-41

Responsive

Breakpoint Changes
Mobile (< 768px) Matrix collapses to card list view (each DE as card showing unit statuses). Filter stacked. p-4
Tablet (768-1023px) Matrix with horizontal scroll. Fewer visible columns. p-6
Desktop (>= 1024px) Full matrix, all columns visible (horizontal scroll if many units). Sticky first column. p-10

Accessibility

  • Matrix: role="grid", header cells role="columnheader", data cells role="gridcell"
  • Cell dots: NOT color alone — tooltip shows status text. aria-label="Số CCCD tại Công an: Lưu trữ"
  • Sticky column: proper z-index so focus ring not cut off
  • Keyboard: Arrow keys to navigate cells, Enter to activate cell action
  • DISPUTED cells: Red color + "DISPUTED" text in tooltip (not color alone)
  • Screen reader: aria-live="polite" for filter changes announcing result count
  • Confirmation alert: role="alert" with aria-label

MASTER.md Overrides

What MASTER.md This Page Reason
Content max-width max-w-6xl max-w-full (no constraint) Matrix needs full available width for many unit columns
Content padding p-10 p-6 xl:p-10 More room for wide matrix on medium screens