US-203: 搜尋與過濾訂單
User Story
作為 店員/管理者 我想要 能夠搜尋和過濾訂單列表 以便 快速找到需要處理的訂單
驗收標準 (Acceptance Criteria)
Scenario 1: 依訂單編號搜尋
- Given 我是已登入的店員
- And 系統中有多筆訂單
- When 我在搜尋框輸入訂單編號(部分或完整)
- Then 系統應顯示符合條件的訂單
Scenario 2: 依訂單狀態過濾
- Given 我是已登入的店員
- When 我選擇訂單狀態過濾條件
- Then 系統應顯示符合所選狀態的訂單
Scenario 3: 組合搜尋與過濾
- Given 我是已登入的店員
- When 我同時使用搜尋和多個過濾條件
- Then 系統應顯示同時符合所有條件的訂單(AND 邏輯)
UI/UX 需求 (UI/UX Requirements)
頁面結構
實作位置: src/applets/order-applet/order-finder.tsx
┌────────────────────────────────────────────────────────────────┐
│ Header Bar (sticky) │
│ [📦 訂單管理] [搜尋框] [重設排序?] [+ 新訂單] │
├───────────────────────────────────────────────┬────────────────┤
│ │ │
│ DataTable │ FilterDrawer │
│ - 訂單編號(連結) │ - 訂單狀態 │
│ - 客戶 │ - 配送日期 │
│ - 金額 │ - 金額區間 │
│ - 配送日期 │ - 分配對象 │
│ - 狀態(Badge) │ │
│ - 操作 │ [清空過濾] │
│ │ │
│ flex-1 │ shrink-0 │
│ │ hidden md:block│
└───────────────────────────────────────────────┴────────────────┘
│ 手機版:FilterFloatingButton(浮動篩選按鈕) │
└────────────────────────────────────────────────────────────────┘
頂部工具列
- 固定位置:
sticky top-0 z-40 bg-base-100 border-b border-base-300 - 左側: 頁面標題(ShoppingBag 圖示 + 「訂單管理」)
- 中間: 搜尋框(SearchBar 組件,支援 debounce)
- 可選: 重設排序按鈕(當排序與預設不同時顯示)
- 右側: 「+ 新訂單」按鈕
DataTable 功能
實作使用: @appfuse/appfuse-web/components 的 DataTable 組件
欄位配置:
| 欄位 | accessorKey | 功能 |
|---|---|---|
| 訂單編號 | orderNumber | Link 至詳情頁,不可隱藏 |
| 客戶 | customerName | 可排序、可隱藏 |
| 金額 | total | 貨幣格式(NT$),可排序、可隱藏 |
| 配送日期 | deliveryDate | 日期格式,可排序、可隱藏 |
| 狀態 | status | OrderStatusBadge,可隱藏 |
| 操作 | actions | 查看、編輯、複製、刪除,不可隱藏 |
進階功能:
- 欄位拖曳排序(
columnOrder) - 欄位顯示/隱藏(
columnVisibility) - 多欄排序(
sorting) - 分頁(
pagination) - 智能格式化(
defaultCellFormatter) - 列序號顯示(
showRowNumber)
過濾面板(FilterDrawer / FilterPanel)
桌面版: 右側固定面板(FilterDrawer)
手機版: 浮動視窗 + 浮動按鈕(FilterFloatingButton)
過濾條件:
- 訂單狀態(多選)
- 配送日期起始
- 配送日期結束
- 最低金額
- 最高金額
- 分配的設計師
- 分配的送貨員
特色功能:
- Debounce 防抖(500ms)
- 已套用過濾標籤(可點擊移除)
- 單欄佈局模式(
singleColumn)
技術規格 (Technical Specifications)
前端組件架構
src/applets/order-applet/
├── order-finder.tsx # 訂單列表頁面
├── components/
│ ├── search-bar.tsx # 搜尋框組件
│ ├── filter-panel.tsx # 過濾面板組件
│ ├── filter-drawer.tsx # 桌面版過濾抽屜
│ ├── filter-floating-button.tsx # 手機版浮動按鈕
│ └── order-status-badge.tsx # 狀態 Badge 組件
src/features/sales/
└── order-finder-slice.ts # 列表狀態管理(Redux)
src/services/sales/
└── order-service.ts # 訂單 Service(query API)
狀態管理(Redux)
Slice: src/features/sales/order-finder-slice.ts
interface OrderFinderState {
searchTerm: string; // 搜尋關鍵字
filters: OrderFilters; // 過濾條件
sorting: SortingState; // 排序狀態
columnOrder: string[]; // 欄位順序
columnVisibility: Record<string, boolean>; // 欄位顯示
currentPage: number; // 當前頁碼
pageSize: number; // 每頁筆數
}
Actions:
setSearchTerm- 設定搜尋關鍵字setFilters- 設定過濾條件setSorting- 設定排序resetSorting- 重設排序setColumnOrder- 設定欄位順序setColumnVisibility- 設定欄位顯示setCurrentPage- 設定頁碼setPageSize- 設定每頁筆數
查詢機制(Predicate)
使用 @appfuse/appfuse-web/utils 的 Predicate 類建構查詢條件:
const predicate = Predicate.empty()
.and(Predicate.like('orderNumber', searchTerm))
.and(Predicate.in('status', filters.status))
.and(Predicate.ge('deliveryDate', filters.deliveryDateFrom))
.and(Predicate.le('deliveryDate', filters.deliveryDateTo))
.and(Predicate.ge('total', filters.amountMin))
.and(Predicate.le('total', filters.amountMax))
.and(Predicate.eq('assignedFlorist', filters.assignedFlorist))
.and(Predicate.eq('assignedDelivery', filters.assignedDelivery))
API 調用
const result = await orderService.query({
predicate: predicate.toString(),
page: currentPage - 1, // 0-indexed
size: pageSize,
sort: 'deliveryDate,asc',
})
前端依賴
框架組件:
DataTable- 表格組件(含排序、分頁、欄位控制)Button,Dropdown- UI 組件prompt- Toast 通知
工具:
Predicate- 查詢條件建構器i18n- 國際化logger,ErrorResponse- 錯誤處理
圖示:
lucide-react: ShoppingBag, X, SlidersHorizontal, Eye, MoreVertical, Trash2, Copy, Pencil
估算 (Estimation)
- Story Points: 5 點
- 預估工時: 2-3 天
- 複雜度: 中等
依賴 (Dependencies)
前置條件
- US-201: 創建訂單 - 需要訂單資料
- US-202: 訂單狀態流轉 - 需要狀態定義
並行開發
- 可與 US-201、US-202 並行開發
完成定義 (Definition of Done)
- DataTable 顯示訂單列表
- 搜尋框支援訂單編號搜尋
- 過濾面板支援多條件過濾
- 欄位拖曳與顯示/隱藏功能
- 分頁導航正常運作
- 響應式設計(桌面版/手機版)
- Redux 狀態持久化
- 空結果友善提示
最後更新: 2025-12-03