跳至主要内容

US-102: 商品列表與搜尋

User Story

作為 花店員工 我想要 能夠瀏覽商品列表並透過搜尋和過濾快速找到商品 以便 在創建訂單時快速選擇商品,或管理商品目錄


驗收標準 (Acceptance Criteria)

Scenario 1: 查看商品列表(預設狀態)

  • Given 我是已登入的員工
  • And 我在「商品管理」頁面
  • When 頁面載入完成
  • Then 我應看到商品列表,預設顯示:
    • 所有「已上架」商品
    • 按創建日期倒序排列(最新的在前)
    • 每頁顯示 20 筆
  • And 每個商品項目應顯示:
    • 商品縮圖
    • 商品名稱
    • SKU 編號
    • 商品類型標籤
    • 基礎價格
    • 庫存狀態(正常/低庫存/缺貨)
    • 上架狀態(已上架/已下架)

Scenario 2: 搜尋商品(依名稱)

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • And 系統中有商品「玫瑰花束(12 朵)」和「百合花束」
  • When 我在搜尋框輸入「玫瑰」
  • Then 列表應即時過濾(防抖 300ms)
  • And 只顯示名稱包含「玫瑰」的商品
  • And 搜尋結果數量應顯示在列表上方

Scenario 3: 搜尋商品(依 SKU)

  • Given 我是已登入的員工
  • And 系統中有 SKU 為「ABC-BQT-000001」的商品
  • When 我在搜尋框輸入「BQT-000001」
  • Then 列表應顯示 SKU 包含「BQT-000001」的商品

Scenario 4: 過濾商品(依類型)

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • When 我選擇類型過濾為「花束」
  • Then 列表應只顯示類型為「花束」的商品
  • And 過濾條件應顯示為「篩選中」標籤

Scenario 5: 過濾商品(依上架狀態)

  • Given 我是已登入的管理者
  • And 我在商品列表頁面
  • When 我選擇狀態過濾為「已下架」
  • Then 列表應只顯示狀態為「已下架」的商品

Scenario 6: 過濾商品(依庫存狀態)

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • When 我選擇庫存狀態過濾為「低庫存」
  • Then 列表應只顯示庫存 <= 低庫存警戒值的商品

Scenario 7: 過濾商品(依價格區間)

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • When 我設定價格區間為「500 ~ 1500」
  • Then 列表應只顯示基礎價格在 500 到 1500 之間的商品

Scenario 8: 組合搜尋與過濾

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • When 我在搜尋框輸入「玫瑰」
  • And 我選擇類型過濾為「花束」
  • And 我選擇價格區間為「1000 ~ 2000」
  • Then 列表應只顯示同時符合以下條件的商品:
    • 名稱或 SKU 包含「玫瑰」
    • 類型為「花束」
    • 價格在 1000 ~ 2000 之間

Scenario 9: 排序商品

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • When 我選擇排序為「價格(高→低)」
  • Then 列表應按基礎價格由高到低排序

Scenario 10: 分頁導航

  • Given 我是已登入的員工
  • And 系統中有 50 筆商品
  • And 每頁顯示 20 筆
  • When 我點擊「下一頁」
  • Then 我應看到第 21-40 筆商品
  • And 分頁指示器應顯示「第 2 頁,共 3 頁」

Scenario 11: 清除所有篩選條件

  • Given 我是已登入的員工
  • And 我已套用多個篩選條件
  • When 我點擊「清除篩選」按鈕
  • Then 所有篩選條件應被重置
  • And 列表應恢復為預設狀態

Scenario 12: 空搜尋結果

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • When 我搜尋「不存在的商品」
  • Then 列表應顯示空狀態訊息「找不到符合條件的商品」
  • And 應顯示「清除篩選」按鈕

Scenario 13: 點擊商品進入詳情頁

  • Given 我是已登入的員工
  • And 我在商品列表頁面
  • When 我點擊商品「玫瑰花束(12 朵)」
  • Then 我應被導航至該商品的詳情頁

業務規則 (Business Rules)

  1. 預設顯示規則

    • 預設只顯示「已上架」商品
    • 管理者可選擇查看「已下架」商品
    • 按創建日期倒序排列
  2. 搜尋規則

    • 搜尋範圍:商品名稱、SKU 編號、商品描述
    • 模糊搜尋(包含即匹配)
    • 不區分大小寫
    • 搜尋關鍵字至少 1 個字元
    • 即時搜尋(防抖 300ms)
  3. 過濾條件

    • 商品類型: 花束/盆花/高架/花籃/盒花/禮品/客製化(可多選)
    • 上架狀態: 已上架/已下架(單選)
    • 庫存狀態: 正常/低庫存/缺貨(可多選)
    • 價格區間: 最低價 ~ 最高價
    • 特殊標記: 熱門商品/新品(可多選)
  4. 排序選項

    • 創建日期(最新/最舊)- 預設
    • 更新日期(最新/最舊)
    • 價格(高→低/低→高)
    • 名稱(A-Z/Z-A)
    • 庫存數量(高→低/低→高)
  5. 分頁規則

    • 每頁 20 筆(可選 10/20/50)
    • 顯示總筆數與頁數
    • URL 參數保留搜尋/過濾/排序/分頁狀態
  6. 庫存狀態定義

    • 正常: 庫存 > 低庫存警戒值
    • 低庫存: 0 < 庫存 <= 低庫存警戒值
    • 缺貨: 庫存 = 0
  7. 權限規則

    • ROLE_STAFF 以上可查看商品列表
    • ROLE_STAFF 只能看到「已上架」商品
    • ROLE_MANAGER 以上可切換查看「已下架」商品
    • 成本價格欄位僅 ROLE_MANAGER 以上可見
  8. 多租戶隔離

    • 列表僅顯示當前租戶的商品
    • API 自動過濾 tenantId

UI/UX 需求 (UI/UX Requirements)

頁面佈局

頂部區域

  • 標題: 商品管理
  • 操作按鈕: 「新增商品」(管理者以上)

搜尋與過濾區域

  • 搜尋框:

    • Placeholder: 「搜尋商品名稱或 SKU...」
    • 搜尋圖示
    • 清除按鈕(有內容時顯示)
  • 過濾器列表:

    • 商品類型(多選下拉)
    • 上架狀態(單選下拉)
    • 庫存狀態(多選下拉)
    • 價格區間(雙滑桿或兩個輸入框)
    • 特殊標記(多選下拉)
  • 排序: 下拉選單

  • 篩選標籤: 已套用的篩選條件顯示為標籤,可點擊 X 移除

  • 清除篩選: 按鈕(有任何篩選時顯示)

列表區域

  • 列表視圖:

    • 表格形式(桌面)
    • 卡片形式(手機)
  • 表格欄位:

    欄位寬度說明
    縮圖60px商品主圖縮圖
    商品名稱auto含 SKU 編號(副標題)
    類型80px商品類型標籤
    價格100px基礎價格
    庫存80px庫存數量 + 狀態標籤
    狀態80px上架/下架標籤
    操作100px編輯、更多選單

分頁區域

  • 左側: 「顯示第 X-Y 筆,共 Z 筆」
  • 中間: 分頁按鈕(首頁、上一頁、頁碼、下一頁、末頁)
  • 右側: 每頁筆數選擇(10/20/50)

狀態標籤樣式

  • 上架狀態:

    • 已上架: 綠色背景
    • 已下架: 灰色背景
  • 庫存狀態:

    • 正常: 無特殊標記
    • 低庫存: 橘色背景「低庫存」
    • 缺貨: 紅色背景「缺貨」
  • 特殊標記:

    • 熱門商品: 星星圖示 + 黃色標籤
    • 新品: 「NEW」標籤

互動行為

  • 搜尋:

    • 輸入後 300ms 自動搜尋
    • 搜尋中顯示 Loading 指示器
    • 搜尋結果數量更新
  • 過濾:

    • 選擇後即時套用
    • 多個過濾條件為 AND 關係
    • 過濾條件顯示為標籤
  • 排序:

    • 選擇後即時排序
    • 當前排序選項顯示為已選中
  • 分頁:

    • 點擊頁碼/箭頭切換頁面
    • 切換頁面時平滑捲動到頂部
    • URL 更新(支援書籤)
  • 空狀態:

    • 顯示插圖 + 文字說明
    • 提供「清除篩選」或「新增商品」按鈕

響應式設計

  • 桌面 (>= 1024px):

    • 表格視圖
    • 過濾器水平排列
  • 平板 (768px ~ 1023px):

    • 表格視圖(隱藏部分欄位)
    • 過濾器可摺疊
  • 手機 (< 768px):

    • 卡片視圖
    • 過濾器在 Drawer 中
    • 「篩選」按鈕顯示已套用數量

技術規格 (Technical Specifications)

API 端點

獲取商品列表

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

Query Parameters:

參數類型必填說明預設值
searchstringNo搜尋關鍵字-
categorystring[]No商品類型(可多選)-
statusstringNo上架狀態 (active/inactive)active
stockStatusstring[]No庫存狀態 (normal/low/out)-
minPricenumberNo最低價格-
maxPricenumberNo最高價格-
isFeaturedbooleanNo熱門商品-
isNewbooleanNo新品-
sortBystringNo排序欄位createdAt
sortOrderstringNo排序方向 (asc/desc)desc
pagenumberNo頁碼(從 1 開始)1
limitnumberNo每頁筆數20

請求範例:

GET /api/v1/products?search=玫瑰&category=bouquet&status=active&minPrice=1000&maxPrice=2000&sortBy=basePrice&sortOrder=desc&page=1&limit=20

響應 Payload:

{
"data": [
{
"id": "prod-abc123",
"sku": "ABC-BQT-000001",
"name": "玫瑰花束(12 朵)",
"description": "經典浪漫,情人節首選",
"category": "bouquet",
"categoryLabel": "花束",
"basePrice": 1200,
"costPrice": 800, // 僅 ROLE_MANAGER 以上可見
"stock": 50,
"lowStockThreshold": 5,
"stockStatus": "normal", // "normal" | "low" | "out"
"status": "active",
"isFeatured": true,
"isNew": false,
"mainImageUrl": "https://...",
"thumbnailUrl": "https://...",
"createdAt": "2025-12-03T10:00:00Z",
"updatedAt": "2025-12-03T10:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 45,
"totalPages": 3
}
}

響應 Headers:

X-Total-Count: 45
X-Page: 1
X-Per-Page: 20
X-Total-Pages: 3

前端狀態管理

使用 URL Search Params 保存搜尋/過濾/排序/分頁狀態:

// URL 範例
/products?search=玫瑰&category=bouquet&status=active&sortBy=basePrice&sortOrder=desc&page=1

// React Hook 範例
const useProductListParams = () => {
const [searchParams, setSearchParams] = useSearchParams();

return {
search: searchParams.get('search') || '',
category: searchParams.getAll('category'),
status: searchParams.get('status') || 'active',
stockStatus: searchParams.getAll('stockStatus'),
minPrice: searchParams.get('minPrice') ? Number(searchParams.get('minPrice')) : undefined,
maxPrice: searchParams.get('maxPrice') ? Number(searchParams.get('maxPrice')) : undefined,
sortBy: searchParams.get('sortBy') || 'createdAt',
sortOrder: searchParams.get('sortOrder') || 'desc',
page: Number(searchParams.get('page')) || 1,
limit: Number(searchParams.get('limit')) || 20,
};
};

元件架構

src/applets/product-applet/
├── ProductListPage.tsx # 商品列表頁面
├── components/
│ ├── ProductSearchBar.tsx # 搜尋框組件
│ ├── ProductFilterPanel.tsx # 過濾面板組件
│ ├── ProductFilterDrawer.tsx # 過濾 Drawer(手機)
│ ├── ProductTable.tsx # 商品表格(桌面)
│ ├── ProductCardList.tsx # 商品卡片列表(手機)
│ ├── ProductListItem.tsx # 單一商品列表項
│ ├── ProductSortSelect.tsx # 排序選擇器
│ └── ProductPagination.tsx # 分頁組件
├── hooks/
│ ├── useProductList.ts # 商品列表 Query Hook
│ └── useProductListParams.ts # URL 參數 Hook
└── types.ts # TypeScript 類型定義

測試需求 (Test Requirements)

單元測試

  • 搜尋邏輯(模糊搜尋、防抖)
  • 過濾邏輯(類型、狀態、價格區間)
  • 排序邏輯(各欄位、升降序)
  • 分頁邏輯(頁碼計算、邊界條件)
  • URL 參數解析與序列化

整合測試

  • 商品列表 API 整合(含搜尋/過濾/排序/分頁)
  • 權限控制(STAFF vs MANAGER 可見欄位差異)
  • 多租戶隔離

E2E 測試

  • Scenario 1: 查看商品列表(預設狀態)
  • Scenario 2: 搜尋商品(依名稱)
  • Scenario 3: 搜尋商品(依 SKU)
  • Scenario 4: 過濾商品(依類型)
  • Scenario 8: 組合搜尋與過濾
  • Scenario 9: 排序商品
  • Scenario 10: 分頁導航
  • Scenario 11: 清除所有篩選條件
  • Scenario 12: 空搜尋結果

驗收檢查清單 (Acceptance Checklist)

  • 商品列表正確顯示
  • 搜尋功能正常(名稱、SKU、即時搜尋)
  • 過濾功能正常(類型、狀態、庫存、價格)
  • 排序功能正常(各欄位、升降序)
  • 分頁功能正常
  • URL 參數正確保存/還原
  • 組合搜尋與過濾正常運作
  • 清除篩選功能正常
  • 空狀態顯示正確
  • 響應式設計正常(桌面/平板/手機)
  • 庫存狀態標籤正確顯示
  • 權限控制正確(成本價格可見性)
  • 點擊商品跳轉詳情頁正常

Story Points

估算: 5 points

理由:

  • 列表、搜尋、過濾、排序、分頁都是常見模式
  • 可參考 US-302(客戶列表與搜尋)實作
  • URL 參數狀態管理增加少許複雜度
  • 響應式設計(表格 vs 卡片)需要額外工作

相關文檔


最後更新: 2025-12-03 撰寫者: AI Assistant