# 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` 頁面都在 `<script>` 標籤前加入：
```html
<script src="draft-utils.js"></script>
```

然後使用 `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. **功能完整** - 提供豐富的工具函數支援各種操作需求 