跳至主要内容

US-301: 客戶基本資料管理

User Story

作為 店員 我想要 能夠新增、編輯、查看和停用客戶資料 以便 管理客戶資訊並避免重複建檔


驗收標準 (Acceptance Criteria)

Scenario 1: 快速新增個人客戶(僅必填欄位)

  • Given 我是已登入的店員
  • And 我在「新增客戶」頁面
  • When 我選擇客戶類型為「個人客戶」
  • And 我填寫姓名「王小明」
  • And 我填寫電話「0912-345-678」
  • And 我點擊「儲存」按鈕
  • Then 系統應創建客戶並自動分配客戶編號(格式:{租戶代碼}-CUST-{流水號}
  • And 我應看到客戶創建成功的通知
  • And 系統應自動導航至客戶詳情頁
  • And 客戶狀態應為「啟用」

Scenario 2: 新增企業客戶(含聯絡人資訊)

  • Given 我是已登入的店員
  • And 我在「新增客戶」頁面
  • When 我選擇客戶類型為「企業客戶」
  • And 我填寫公司名稱「XX 科技股份有限公司」
  • And 我填寫統一編號「12345678」
  • And 我填寫公司電話「02-1234-5678」
  • And 我添加聯絡人「張經理」,電話「0912-111-222」,設為主要聯絡人
  • And 我點擊「儲存」按鈕
  • Then 系統應創建企業客戶
  • And 聯絡人資訊應正確儲存
  • And 主要聯絡人應有特殊標記

Scenario 3: 重複電話檢測(新增時)

  • Given 我是已登入的店員
  • And 系統中已存在電話為「0912-345-678」的客戶「王小明」
  • When 我嘗試新增新客戶
  • And 我填寫電話「0912-345-678」
  • And 我填寫姓名「王大明」
  • And 我點擊「儲存」按鈕
  • Then 系統應顯示警告訊息「此電話已被客戶『王小明』使用」
  • And 系統應詢問「是否繼續創建?」
  • And 若我選擇「取消」,則不創建新客戶
  • And 若我選擇「繼續」,則允許創建(可能是家人共用電話)

Scenario 4: 編輯客戶基本資訊

  • Given 我是已登入的店員
  • And 我在客戶「王小明」的詳情頁
  • When 我點擊「編輯」按鈕
  • And 我修改電話為「0912-999-888」
  • And 我添加 Email「wang@example.com
  • And 我添加生日「1990-05-15」
  • And 我點擊「儲存」按鈕
  • Then 系統應更新客戶資訊
  • And 我應看到「儲存成功」的通知
  • And 更新應立即反映在詳情頁

Scenario 5: 停用客戶

  • Given 我是已登入的管理者
  • And 我在客戶「王小明」的詳情頁
  • When 我點擊「停用客戶」按鈕
  • And 系統要求我填寫停用原因
  • And 我選擇停用原因為「黑名單客戶(惡意退貨)」
  • And 我填寫備註「多次無理由退貨」
  • And 我點擊「確認停用」按鈕
  • Then 系統應將客戶狀態改為「停用」
  • And 停用原因與備註應記錄在審計日誌
  • And 此客戶不應再出現在創建訂單時的客戶選擇列表
  • And 但歷史訂單仍可正常查看

Scenario 6: 重新啟用客戶

  • Given 我是已登入的管理者
  • And 客戶「王小明」目前狀態為「停用」
  • When 我點擊「重新啟用」按鈕
  • And 系統要求我確認
  • And 我點擊「確認」按鈕
  • Then 系統應將客戶狀態改為「啟用」
  • And 此客戶應重新出現在客戶選擇列表

Scenario 7: 新增客戶時缺少必填欄位(錯誤場景)

  • Given 我是已登入的店員
  • And 我在「新增客戶」頁面
  • When 我僅填寫姓名「王小明」(未填寫電話)
  • And 我點擊「儲存」按鈕
  • Then 系統應顯示錯誤訊息「請填寫電話」
  • And 電話欄位應以紅色邊框標示
  • And 客戶不應被創建
  • And 表單應保留我已填寫的資料

業務規則 (Business Rules)

  1. 客戶編號規則

    • 格式: {租戶代碼}-CUST-{流水號}
    • 範例: ABC-CUST-000001
    • 流水號從 000001 開始,每次創建新客戶遞增
  2. 個人客戶必填欄位

    • 姓名
    • 電話
  3. 企業客戶必填欄位

    • 公司名稱
    • 公司電話
    • 至少一位聯絡人(含姓名與電話)
  4. 電話格式驗證

    • 支援格式: 09XX-XXX-XXX, 0912345678, 02-XXXX-XXXX
    • 自動移除空格與連字號後儲存
    • 查詢時不區分格式(統一比對純數字)
  5. 重複檢測規則

    • 新增客戶時檢查電話是否重複
    • 編輯客戶時若修改電話,也需檢查重複
    • 允許用戶忽略警告並強制創建(可能是家人共用電話)
  6. 停用/啟用權限

    • ROLE_MANAGER 或更高權限可停用/啟用客戶
    • 停用時必須填寫停用原因
    • 停用客戶的歷史訂單仍保留且可查看
  7. 多租戶隔離

    • 客戶自動關聯到當前用戶的 tenantId
    • 客戶列表僅顯示當前租戶的客戶
  8. 客戶等級計算

    • 累計消費 < 5,000: 普通客戶
    • 累計消費 >= 5,000: VIP
    • 累計消費 >= 20,000: VVIP
    • 等級自動計算,無法手動修改

UI/UX 需求 (UI/UX Requirements)

新增/編輯客戶表單佈局

個人客戶表單

  • 基本資訊區:

    • 姓名(必填)
    • 性別(選填,單選:男/女/其他)
    • 生日(選填,日期選擇器)
    • 電話(必填)
    • Email(選填)
  • 地址資訊區 (可摺疊):

    • 地址列表(可多筆)
    • 「新增地址」按鈕
    • 設定預設地址
  • 附加資訊區 (可摺疊):

    • 客戶來源(下拉選單)
    • 喜好標籤(多選)
    • 重要日期(如:結婚紀念日)

企業客戶表單

  • 基本資訊區:

    • 公司名稱(必填)
    • 統一編號(選填,8 位數字驗證)
    • 產業類別(下拉選單)
    • 公司電話(必填)
    • 公司地址(選填)
    • Email(選填)
  • 聯絡人資訊區:

    • 聯絡人列表(表格顯示)
    • 每個聯絡人包含:姓名、職稱、電話、Email、是否主要聯絡人
    • 「新增聯絡人」按鈕
    • 至少需要一位聯絡人
  • 附加資訊區 (可摺疊):

    • 合作開始日期(日期選擇器)
    • 月結帳期(下拉選單:無/月結 15 天/月結 30 天)

客戶詳情頁佈局

  • 客戶資訊卡片:

    • 客戶編號(唯讀)
    • 客戶等級徽章(VIP/VVIP)
    • 客戶狀態(啟用/停用)
    • 註冊日期
    • 最後消費日期
    • 累計消費金額
  • 操作按鈕:

    • 編輯(所有用戶)
    • 停用/啟用(僅管理者)
    • 合併客戶(僅管理者,P2 功能)

互動行為

  • 重複檢測: 輸入電話後自動檢查(防抖 500ms)

    • 若重複,顯示警告訊息與現有客戶連結
    • 用戶可選擇「查看現有客戶」或「繼續創建」
  • 聯絡人管理 (企業客戶):

    • 「新增聯絡人」按鈕開啟內嵌表單
    • 「設為主要聯絡人」單選按鈕(僅一位)
    • 刪除聯絡人時若為主要聯絡人,需先設定其他人為主要聯絡人
  • 停用確認:

    • 點擊「停用客戶」按鈕開啟 Modal
    • Modal 包含停用原因選擇與備註輸入
    • 需二次確認

錯誤訊息

  • 缺少必填欄位: 紅色邊框 + 欄位下方顯示錯誤訊息
  • 電話格式錯誤: 「請輸入正確的電話格式」
  • 統一編號格式錯誤: 「請輸入 8 位數字」
  • 重複電話警告: 黃色警告框 + 「此電話已被客戶『XXX』使用」

成功反饋

  • 客戶創建成功: Toast 通知「客戶 {編號} 創建成功」
  • 客戶更新成功: Toast 通知「儲存成功」
  • 客戶停用成功: Toast 通知「客戶已停用」

響應式設計

  • 桌面: 雙欄佈局(左側表單,右側客戶資訊預覽)
  • 平板/手機: 單欄佈局(垂直排列)

技術規格 (Technical Specifications)

API 端點

1. 創建客戶

  • 端點: POST /api/v1/customers
  • 權限要求: ROLE_STAFF 或更高
  • 多租戶隔離: 自動附加 tenantId

請求 Payload (個人客戶):

{
"type": "individual", // 'individual' | 'corporate'
"name": "王小明",
"gender": "male", // 'male' | 'female' | 'other' (選填)
"birthday": "1990-05-15", // ISO 8601 (選填)
"phone": "0912345678",
"email": "wang@example.com", // (選填)
"addresses": [ // (選填)
{
"address": "台北市信義區信義路五段 7 號",
"isDefault": true,
"label": "住家" // (選填)
}
],
"source": "google_search", // 客戶來源 (選填)
"preferences": ["喜歡玫瑰", "不要百合"], // 喜好標籤 (選填)
"importantDates": [ // 重要日期 (選填)
{
"date": "2020-06-01",
"label": "結婚紀念日"
}
]
}

請求 Payload (企業客戶):

{
"type": "corporate",
"companyName": "XX 科技股份有限公司",
"taxId": "12345678", // 統一編號 (選填)
"industry": "technology", // 產業類別 (選填)
"phone": "02-1234-5678",
"address": "台北市信義區信義路五段 100 號", // (選填)
"email": "contact@xxtech.com", // (選填)
"contacts": [
{
"name": "張經理",
"title": "業務經理",
"phone": "0912-111-222",
"email": "chang@xxtech.com",
"isPrimary": true
}
],
"cooperationStartDate": "2025-01-01", // (選填)
"paymentTerms": "net30" // 'none' | 'net15' | 'net30' (選填)
}

響應 Payload:

{
"id": "abc123",
"customerNumber": "ABC-CUST-000001",
"type": "individual",
"name": "王小明",
"phone": "0912345678",
"email": "wang@example.com",
"status": "active", // 'active' | 'inactive'
"tier": "regular", // 'regular' | 'vip' | 'vvip'
"totalSpent": 0,
"totalOrders": 0,
"lastOrderDate": null,
"createdAt": "2025-11-04T10:00:00Z",
"updatedAt": "2025-11-04T10:00:00Z"
}

2. 檢查電話是否重複

  • 端點: GET /api/v1/customers/check-duplicate?phone={phone}
  • 權限要求: ROLE_STAFF 或更高

響應 Payload:

{
"isDuplicate": true,
"existingCustomer": {
"id": "abc123",
"customerNumber": "ABC-CUST-000001",
"name": "王小明",
"phone": "0912345678"
}
}

3. 更新客戶

  • 端點: PUT /api/v1/customers/{id}
  • 權限要求: ROLE_STAFF 或更高

請求 Payload: 同創建客戶(部分欄位更新)

4. 停用/啟用客戶

  • 端點: PATCH /api/v1/customers/{id}/status
  • 權限要求: ROLE_MANAGER 或更高

請求 Payload (停用):

{
"status": "inactive",
"reason": "blacklist", // 'blacklist' | 'duplicate' | 'other'
"reasonNote": "多次無理由退貨"
}

請求 Payload (啟用):

{
"status": "active"
}

前端驗證規則

// Zod Schema (個人客戶)
const IndividualCustomerSchema = z.object({
type: z.literal('individual'),
name: z.string().min(1, '請填寫姓名').max(50, '姓名過長'),
gender: z.enum(['male', 'female', 'other']).optional(),
birthday: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
phone: z.string()
.min(1, '請填寫電話')
.regex(/^[0-9\-\s]+$/, '電話格式錯誤'),
email: z.string().email('Email 格式錯誤').optional().or(z.literal('')),
addresses: z.array(z.object({
address: z.string().min(1, '請填寫地址'),
isDefault: z.boolean(),
label: z.string().optional(),
})).optional(),
source: z.string().optional(),
preferences: z.array(z.string()).optional(),
importantDates: z.array(z.object({
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
label: z.string(),
})).optional(),
});

// Zod Schema (企業客戶)
const CorporateCustomerSchema = z.object({
type: z.literal('corporate'),
companyName: z.string().min(1, '請填寫公司名稱').max(100, '公司名稱過長'),
taxId: z.string().regex(/^\d{8}$/, '統一編號必須為 8 位數字').optional(),
industry: z.string().optional(),
phone: z.string()
.min(1, '請填寫公司電話')
.regex(/^[0-9\-\s]+$/, '電話格式錯誤'),
address: z.string().optional(),
email: z.string().email('Email 格式錯誤').optional().or(z.literal('')),
contacts: z.array(z.object({
name: z.string().min(1, '請填寫聯絡人姓名'),
title: z.string().optional(),
phone: z.string().regex(/^[0-9\-\s]+$/, '電話格式錯誤'),
email: z.string().email('Email 格式錯誤').optional().or(z.literal('')),
isPrimary: z.boolean(),
})).min(1, '至少需要一位聯絡人'),
cooperationStartDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
paymentTerms: z.enum(['none', 'net15', 'net30']).optional(),
});

元件架構

src/applets/customer-applet/
├── CustomerApplet.tsx # 容器組件
├── CustomerForm.tsx # 客戶表單(新增/編輯)
├── CustomerDetailPage.tsx # 客戶詳情頁
├── components/
│ ├── IndividualCustomerForm.tsx # 個人客戶表單
│ ├── CorporateCustomerForm.tsx # 企業客戶表單
│ ├── ContactList.tsx # 聯絡人列表
│ ├── AddressList.tsx # 地址列表
│ └── CustomerStatusBadge.tsx # 客戶狀態徽章
├── hooks/
│ ├── useCustomerForm.ts # 客戶表單邏輯
│ └── useDuplicateCheck.ts # 重複檢測邏輯
└── types.ts # TypeScript 類型定義

測試需求 (Test Requirements)

單元測試

  • 表單驗證邏輯(必填欄位、格式驗證)
  • 電話重複檢測邏輯
  • 客戶等級計算邏輯
  • 聯絡人管理邏輯(新增/刪除/設為主要)

整合測試

  • 創建個人客戶 API 整合
  • 創建企業客戶 API 整合
  • 重複檢測 API 整合
  • 停用/啟用客戶 API 整合

E2E 測試

  • Scenario 1: 快速新增個人客戶
  • Scenario 2: 新增企業客戶(含聯絡人)
  • Scenario 3: 重複電話檢測
  • Scenario 4: 編輯客戶資訊
  • Scenario 5: 停用客戶
  • Scenario 7: 表單驗證錯誤

驗收檢查清單 (Acceptance Checklist)

  • 可創建個人客戶(必填欄位)
  • 可創建企業客戶(含聯絡人)
  • 電話重複檢測功能正常
  • 可編輯客戶資訊
  • 管理者可停用/啟用客戶
  • 停用客戶不出現在選擇列表
  • 表單驗證錯誤訊息正確顯示
  • 響應式設計正常(桌面/手機)
  • 審計日誌記錄正確
  • 多租戶隔離正常

Story Points

估算: 8 points

理由:

  • 需要處理個人客戶與企業客戶兩種類型
  • 包含複雜的表單驗證(必填、格式、重複檢測)
  • 聯絡人管理邏輯較複雜
  • 停用/啟用客戶需要權限檢查

相關文檔


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