跳至主要内容

US-302: 客戶列表與搜尋

User Story

作為 店員 我想要 能夠快速搜尋與過濾客戶列表 以便 找到目標客戶並查看其詳細資訊


驗收標準 (Acceptance Criteria)

Scenario 1: 查看客戶列表(預設排序)

  • Given 我是已登入的店員
  • And 系統中有 50 筆客戶資料
  • When 我進入「客戶管理」頁面
  • Then 系統應顯示客戶列表(預設每頁 20 筆)
  • And 列表應依「註冊日期」降序排列(最新客戶在最上方)
  • And 每筆客戶應顯示:
    • 客戶編號
    • 姓名/公司名稱
    • 客戶類型(個人/企業)
    • 客戶等級徽章(VIP/VVIP)
    • 電話
    • 累計消費金額
    • 最後消費日期
    • 客戶狀態(啟用/停用)
  • And 列表底部應顯示分頁導航(頁碼 1/3,每頁 20 筆)

Scenario 2: 搜尋客戶(姓名)

  • Given 我在「客戶管理」頁面
  • And 系統中有客戶「王小明」與「王大明」
  • When 我在搜尋框輸入「王小明」
  • And 系統防抖 500ms 後自動搜尋
  • Then 列表應僅顯示「王小明」
  • And 搜尋框右側應顯示「清空」按鈕

Scenario 3: 搜尋客戶(部分電話號碼)

  • Given 我在「客戶管理」頁面
  • And 系統中有客戶「王小明」電話「0912-345-678」
  • When 我在搜尋框輸入「0912」
  • Then 列表應顯示電話包含「0912」的所有客戶
  • And 「王小明」應出現在結果中

Scenario 4: 依客戶等級過濾

  • Given 我在「客戶管理」頁面
  • And 系統中有 10 筆 VIP 客戶
  • When 我點擊「過濾」按鈕
  • And 我勾選「客戶等級: VIP」
  • And 我點擊「套用」按鈕
  • Then 列表應僅顯示 VIP 客戶
  • And 過濾條件應以標籤形式顯示在搜尋框下方
  • And 標籤應可單獨移除

Scenario 5: 組合搜尋與過濾(客戶類型 + 日期範圍)

  • Given 我在「客戶管理」頁面
  • When 我勾選「客戶類型: 企業客戶」
  • And 我設定「註冊日期範圍: 2025-10-01 ~ 2025-10-31」
  • And 我點擊「套用」按鈕
  • Then 列表應僅顯示符合條件的企業客戶
  • And 顯示筆數應更新
  • And 過濾條件標籤應顯示「企業客戶」與「2025-10-01 ~ 2025-10-31」

Scenario 6: 清空過濾條件

  • Given 我已套用過濾條件(客戶類型: 企業客戶)
  • When 我點擊過濾條件標籤上的「移除」圖示
  • Then 該過濾條件應被移除
  • And 列表應恢復顯示所有客戶
  • And 分頁應重置為第一頁

Scenario 7: 切換每頁筆數

  • Given 我在「客戶管理」頁面
  • And 當前每頁顯示 20 筆
  • When 我選擇「每頁筆數: 50」
  • Then 列表應重新載入並顯示 50 筆客戶
  • And 分頁資訊應更新

Scenario 8: 排序客戶列表(依累計消費金額)

  • Given 我在「客戶管理」頁面
  • When 我點擊「累計消費金額」欄位標題
  • Then 列表應依累計消費金額降序排列(高 → 低)
  • And 欄位標題應顯示向下箭頭
  • When 我再次點擊「累計消費金額」欄位標題
  • Then 列表應改為升序排列(低 → 高)
  • And 欄位標題應顯示向上箭頭

Scenario 9: 點擊客戶進入詳情頁

  • Given 我在「客戶管理」頁面
  • And 列表中顯示客戶「王小明」
  • When 我點擊「王小明」的客戶編號或姓名
  • Then 系統應導航至客戶詳情頁
  • And 詳情頁應顯示完整的客戶資訊

Scenario 10: 空搜尋結果處理

  • Given 我在「客戶管理」頁面
  • When 我搜尋「不存在的客戶名稱XYZABC」
  • And 系統無任何符合條件的結果
  • Then 列表應顯示「查無符合條件的客戶」訊息
  • And 應顯示「清空搜尋條件」按鈕
  • And 分頁導航應隱藏

Scenario 11: 響應式設計(手機版)

  • Given 我使用手機瀏覽器訪問「客戶管理」頁面
  • Then 列表應以卡片形式顯示(非表格)
  • And 每張卡片應包含:
    • 客戶編號與等級徽章
    • 姓名/公司名稱
    • 電話
    • 累計消費金額
    • 最後消費日期
  • And 過濾面板應以摺疊方式顯示

業務規則 (Business Rules)

  1. 預設排序

    • 初次進入頁面: 依註冊日期降序(最新客戶在上)
    • 用戶可自行切換排序欄位與順序
  2. 搜尋邏輯

    • 支援模糊搜尋(姓名/公司名稱/電話/地址)
    • 不區分大小寫
    • 防抖延遲: 500ms
    • 電話搜尋支援部分號碼匹配
  3. 過濾條件

    • 客戶類型: 個人 / 企業(單選)
    • 客戶等級: 普通 / VIP / VVIP(多選)
    • 客戶狀態: 啟用 / 停用(單選)
    • 客戶標籤: 可多選
    • 註冊日期範圍: 起始日期 ~ 結束日期(閉區間)
    • 最後消費日期範圍: 起始日期 ~ 結束日期(閉區間)
    • 累計消費金額區間: 最低金額 ~ 最高金額(閉區間)
  4. 分頁規則

    • 預設每頁 20 筆
    • 可選: 10 / 20 / 50 / 100 筆/頁
    • 搜尋或過濾變更時,自動重置為第一頁
  5. 停用客戶顯示

    • 預設不顯示停用客戶
    • 若過濾條件選擇「客戶狀態: 停用」,則顯示停用客戶
    • 停用客戶以灰色標示
  6. 多租戶隔離

    • 列表僅顯示當前租戶的客戶
    • API 層級自動過濾

UI/UX 需求 (UI/UX Requirements)

頁面佈局

桌面版

┌─────────────────────────────────────────────────┐
│ 客戶管理 [新增客戶] │
├─────────────────────────────────────────────────┤
│ [搜尋框................................] 🔍 │
│ [過濾條件: 企業客戶 ×] [VIP ×] [過濾 ▼] │
├─────────────────────────────────────────────────┤
│ 客戶編號 姓名 類型 等級 電話 消費金額 │
│ ABC-001 王小明 個人 VIP 0912.. $5,000 │
│ ABC-002 XX公司 企業 VVIP 02-12.. $25,000 │
│ ... │
├─────────────────────────────────────────────────┤
│ 顯示 1-20 / 共 50 筆 [10▼] 筆/頁 [< 1 2 3 >]│
└─────────────────────────────────────────────────┘

手機版(卡片模式)

┌─────────────────────┐
│ [搜尋框.........] 🔍 │
│ [過濾 ▼] │
├─────────────────────┤
│ ┌─────────────────┐ │
│ │ ABC-001 [VIP]│ │
│ │ 王小明 │ │
│ │ 0912-345-678 │ │
│ │ 累計: $5,000 │ │
│ │ 最後: 2025/10/31│ │
│ └─────────────────┘ │
│ ┌─────────────────┐ │
│ │ ABC-002 [VVIP]│ │
│ │ XX 科技公司 │ │
│ │ 02-1234-5678 │ │
│ │ 累計: $25,000 │ │
│ │ 最後: 2025/11/01│ │
│ └─────────────────┘ │
├─────────────────────┤
│ [< 1 2 3 >] │
└─────────────────────┘

互動行為

  1. 搜尋框

    • 左側搜尋圖示
    • 右側清空按鈕(有輸入內容時顯示)
    • 防抖 500ms
    • Placeholder: 「搜尋客戶姓名、電話、地址...」
  2. 過濾面板

    • 點擊「過濾」按鈕展開過濾面板(Dropdown)
    • 面板包含所有過濾條件(客戶類型、等級、狀態、標籤、日期、金額)
    • 「清空所有」按鈕(重置所有過濾條件)
    • 「套用」按鈕(套用並關閉面板)
  3. 過濾條件標籤

    • 顯示在搜尋框下方
    • 每個標籤可單獨移除(點擊 × 圖示)
    • 標籤顏色: DaisyUI badge-primary
  4. 列表表格

    • 點擊欄位標題可排序(升序/降序)
    • 點擊客戶編號或姓名進入詳情頁
    • Hover 時列顯示背景色
    • 停用客戶以灰色標示
  5. 分頁導航

    • 頁碼快速跳轉(1 ... 5 6 7 ... 10)
    • 上一頁/下一頁按鈕
    • 每頁筆數下拉選單
    • 顯示當前範圍與總筆數(「顯示 1-20 / 共 50 筆」)

錯誤訊息

  • API 錯誤: Toast 通知「載入失敗,請稍後再試」
  • 空搜尋結果: 「查無符合條件的客戶」+ 插圖

載入狀態

  • 列表載入中: Skeleton 載入動畫(表格行)
  • 搜尋中: 搜尋框右側顯示 Spinner

技術規格 (Technical Specifications)

API 端點

1. 獲取客戶列表

  • 端點: GET /api/v1/customers
  • 權限要求: ROLE_STAFF 或更高
  • 多租戶隔離: 自動過濾當前租戶

查詢參數:

{
// 搜尋
search?: string, // 搜尋關鍵字(姓名/電話/地址)

// 過濾
type?: 'individual' | 'corporate', // 客戶類型
tier?: ('regular' | 'vip' | 'vvip')[], // 客戶等級(可多選)
status?: 'active' | 'inactive', // 客戶狀態
tags?: string[], // 客戶標籤(可多選)
registeredDateFrom?: string, // 註冊日期起始(ISO 8601)
registeredDateTo?: string, // 註冊日期結束(ISO 8601)
lastOrderDateFrom?: string, // 最後消費日期起始(ISO 8601)
lastOrderDateTo?: string, // 最後消費日期結束(ISO 8601)
totalSpentMin?: number, // 累計消費最低金額
totalSpentMax?: number, // 累計消費最高金額

// 分頁
page?: number, // 頁碼(預設: 1)
limit?: number, // 每頁筆數(預設: 20)

// 排序
sortBy?: 'createdAt' | 'lastOrderDate' | 'totalSpent' | 'name', // 排序欄位
sortOrder?: 'asc' | 'desc', // 排序順序(預設: desc)
}

響應 Payload:

{
"customers": [
{
"id": "abc123",
"customerNumber": "ABC-CUST-000001",
"type": "individual", // 'individual' | 'corporate'
"name": "王小明",
"companyName": null,
"phone": "0912345678",
"email": "wang@example.com",
"status": "active", // 'active' | 'inactive'
"tier": "vip", // 'regular' | 'vip' | 'vvip'
"tags": ["常客", "喜歡玫瑰"],
"totalSpent": 5000,
"totalOrders": 8,
"lastOrderDate": "2025-10-31T10:00:00Z",
"createdAt": "2025-01-15T10:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"totalPages": 3,
"totalItems": 50
}
}

前端狀態管理

// 搜尋與過濾狀態
interface CustomerListState {
// 搜尋
searchQuery: string;

// 過濾
filters: {
type?: 'individual' | 'corporate';
tier: ('regular' | 'vip' | 'vvip')[];
status?: 'active' | 'inactive';
tags: string[];
registeredDateFrom?: string;
registeredDateTo?: string;
lastOrderDateFrom?: string;
lastOrderDateTo?: string;
totalSpentMin?: number;
totalSpentMax?: number;
};

// 分頁
pagination: {
page: number;
limit: number;
};

// 排序
sort: {
sortBy: 'createdAt' | 'lastOrderDate' | 'totalSpent' | 'name';
sortOrder: 'asc' | 'desc';
};

// 數據
customers: Customer[];
totalPages: number;
totalItems: number;

// 載入狀態
isLoading: boolean;
error: string | null;
}

元件架構

src/applets/customer-applet/
├── CustomersPage.tsx # 客戶列表主頁面
├── components/
│ ├── CustomerSearchBar.tsx # 搜尋框組件
│ ├── CustomerFilterPanel.tsx # 過濾面板
│ ├── CustomerFilterTags.tsx # 過濾條件標籤
│ ├── CustomerTable.tsx # 客戶表格(桌面)
│ ├── CustomerCardList.tsx # 客戶卡片列表(手機)
│ ├── CustomerPagination.tsx # 分頁導航
│ └── CustomerTierBadge.tsx # 客戶等級徽章
├── hooks/
│ ├── useCustomerList.ts # 客戶列表邏輯
│ └── useCustomerFilters.ts # 過濾邏輯
└── types.ts # TypeScript 類型定義

測試需求 (Test Requirements)

單元測試

  • 搜尋防抖邏輯
  • 過濾條件構建邏輯
  • 排序邏輯
  • 分頁導航邏輯

整合測試

  • 客戶列表 API 整合
  • 搜尋功能整合
  • 過濾功能整合
  • 分頁功能整合

E2E 測試

  • Scenario 1: 查看客戶列表
  • Scenario 2: 搜尋客戶(姓名)
  • Scenario 3: 搜尋客戶(電話)
  • Scenario 4: 依客戶等級過濾
  • Scenario 5: 組合搜尋與過濾
  • Scenario 6: 清空過濾條件
  • Scenario 7: 切換每頁筆數
  • Scenario 8: 排序客戶列表
  • Scenario 9: 點擊客戶進入詳情頁
  • Scenario 10: 空搜尋結果
  • Scenario 11: 響應式設計

驗收檢查清單 (Acceptance Checklist)

  • 客戶列表正確顯示(預設排序)
  • 搜尋功能正常(姓名/電話)
  • 過濾功能正常(類型/等級/狀態/標籤/日期/金額)
  • 組合搜尋與過濾功能正常
  • 清空過濾條件功能正常
  • 分頁導航功能正常
  • 切換每頁筆數功能正常
  • 排序功能正常(升序/降序)
  • 點擊客戶進入詳情頁
  • 空搜尋結果處理正確
  • 響應式設計正常(桌面/手機)
  • 載入狀態正確顯示
  • 錯誤處理正確

Story Points

估算: 5 points

理由:

  • 基本的列表、搜尋、過濾、分頁功能
  • 需要處理多種過濾條件組合
  • 需要響應式設計(表格/卡片模式)
  • 類似 US-203(訂單搜尋與過濾)

相關文檔


最後更新: 2025-11-04 撰寫者: Product Team