# Draft 欄位改進方案 ## 問題描述 原本的 `draft` 欄位被用於兩種不同目的,導致資料結構混亂: 1. **暫存沖帳分配** - 在個人沖帳流程中暫存使用者的沖帳金額分配 2. **歷史沖帳記錄** - 記錄已完成的沖帳明細 這導致兩種不同用途的資料互相覆蓋,造成資料不一致的問題。 ## 改進方案 將原本的純陣列格式改為物件格式,包含兩個子陣列: ### 新的 draft 欄位格式 ```json { "transfer_draft": [ { "pro_order_detail_num": "訂單明細編號", "reconcile": "沖帳金額" } ], "pro_order_detail_items": [ { "pro_order_detail_num": "訂單明細編號", "reconcile": "沖帳金額", "activity_name": "活動名稱", "actitem_name": "項目名稱", "price": "原始金額", "register_date": "報名日期", "order_no": "訂單編號" } ] } ``` ### 1. `transfer_draft` - 暫存沖帳分配 **用途:** - 在 `personal_reconcile.aspx` 中暫存使用者的沖帳金額分配 - 顯示 📝 圖示表示有暫存資料 - 支援「暫存」和「重新分配」功能 ### 2. `pro_order_detail_items` - 沖帳明細記錄 **用途:** - 在 `balance_reconcile.aspx` 中顯示歷史沖帳記錄 - 在 `balance_reconcile_query.aspx` 中顯示選取項目 - 包含完整的活動和項目資訊 ## 向後相容性 程式碼會自動檢測格式並處理: ### 新格式(物件) ```json { "transfer_draft": [...], "pro_order_detail_items": [...] } ``` ### 舊格式(陣列) ```json [ { "pro_order_detail_num": "12345", "reconcile": 5000 } ] ``` ## 修改的檔案 ### personal_reconcile.aspx - 更新 `loadFromDraftOrAutoDistribute()` 方法支援新舊格式 - 更新 `saveDraft()` 方法使用新格式 - 新增 `hasTransferDraft()` 方法檢查暫存資料 - 更新顯示邏輯使用新格式 ### balance_reconcile.aspx - 更新歷史記錄載入邏輯支援新格式 - 更新詳細資訊顯示邏輯支援新格式 - 保持向後相容性 ### balance_reconcile_query.aspx - 更新 `getDraftItems()` 方法支援新舊格式 - 更新項目顯示邏輯 ## 資料安全保護機制 為了確保 `transfer_draft` 和 `pro_order_detail_items` 的操作互不影響,實作了以下保護機制: ### 1. 統一工具函數 所有頁面都使用統一的 `draft-utils.js` 工具函數: - `window.DraftUtils.getDraftObject(draft)` - 安全解析 draft 欄位 - `window.DraftUtils.getDraftField(draft, fieldName)` - 安全取得特定欄位 - `window.DraftUtils.updateDraftField(draft, fieldName, newValue)` - 安全更新特定欄位 - `window.DraftUtils.hasTransferDraft(draft)` - 檢查是否有暫存資料 - `window.DraftUtils.hasProOrderDetailItems(draft)` - 檢查是否有歷史記錄 ### 2. 操作範例 **更新 transfer_draft(不會影響 pro_order_detail_items):** ```javascript const currentDraft = this.dialog.selected.draft || ''; const newTransferDraft = this.dialog.items .filter(item => Number(item.reconcile) > 0) .map(item => ({ pro_order_detail_num: item.num, reconcile: Number(item.reconcile) })); const newDraftObj = window.DraftUtils.updateDraftField(currentDraft, 'transfer_draft', newTransferDraft); ``` **更新 pro_order_detail_items(不會影響 transfer_draft):** ```javascript const currentDraft = item.draft || ''; const newDetailItems = [ { pro_order_detail_num: "123", reconcile: 5000, activity_name: "法會", actitem_name: "護持金" } ]; const newDraftObj = window.DraftUtils.updateDraftField(currentDraft, 'pro_order_detail_items', newDetailItems); ``` **檢查是否有暫存資料:** ```javascript if (window.DraftUtils.hasTransferDraft(item.draft)) { console.log('有暫存資料'); } ``` **取得特定欄位:** ```javascript const transferDraft = window.DraftUtils.getDraftField(item.draft, 'transfer_draft'); const detailItems = window.DraftUtils.getDraftField(item.draft, 'pro_order_detail_items'); ``` ### 3. 統一工具檔案 建立了 `draft-utils.js` 統一工具檔案,所有頁面都引用此檔案: - 所有 draft 操作函數統一管理 - 格式驗證功能 - 向後相容性處理 - 詳細的使用範例 - 避免程式碼重複,提升維護性 ### 4. 頁面引用方式 每個 `.aspx` 頁面都在 ` ``` 然後使用 `window.DraftUtils` 來呼叫工具函數,確保所有頁面使用相同的邏輯。 ### 5. 完整工具函數清單 `draft-utils.js` 提供以下工具函數: **基本操作:** - `getDraftObject(draft)` - 解析 draft 欄位,返回標準化物件 - `getDraftField(draft, fieldName)` - 安全取得特定欄位 - `updateDraftField(draft, fieldName, newValue)` - 安全更新特定欄位 - `clearDraftField(draft, fieldName)` - 清除特定欄位 **檢查函數:** - `hasTransferDraft(draft)` - 檢查是否有暫存資料 - `hasProOrderDetailItems(draft)` - 檢查是否有歷史記錄 **工具函數:** - `mergeDraftObjects(draft1, draft2)` - 合併兩個 draft 物件 - `validateDraftFormat(draft)` - 驗證 draft 格式 - `getDraftSummary(draft)` - 取得 draft 摘要資訊 - `migrateLegacyFormat(draft)` - 將舊格式轉換為新格式 - `cleanEmptyDraft(draft)` - 清理空的 draft 欄位 - `formatDraftJson(draft)` - 格式化 draft JSON 為可讀字串 ## 優點 1. **職責分離** - 每個子陣列有明確的用途 2. **資料一致性** - 避免不同用途的資料互相覆蓋 3. **向後相容** - 支援舊格式,無需資料庫變更 4. **易於維護** - 程式碼邏輯更清晰 5. **擴展性** - 未來可以添加更多子陣列 6. **資料安全** - 確保各欄位操作互不影響 7. **程式碼統一** - 所有頁面使用相同的工具函數 8. **功能完整** - 提供豐富的工具函數支援各種操作需求