# Job 批次設置匯入匯出 — 前端整合規格

## 功能概述

新增 Job 批次設置的匯入匯出功能，讓使用者透過 Excel 一次設定專案內所有 Job 的任務類型、指派人員、參與部門、設備。

---

## 功能流程

```
Step 1: 匯出 Excel
  GET /export → 瀏覽器下載 .xlsx（A 欄隱藏 job_uid，可編輯欄位為淡黃底）

Step 2: 上傳 Excel
  POST /import (multipart/form-data) → 回傳驗證結果

Step 3: 驗證結果預覽
  → 有效行 ✓ / 錯誤行 ✗（標紅，顯示錯誤訊息）
  → 使用者可在表格中直接編輯修正

Step 4: 重新驗證（可重複多次）
  POST /import/validate (JSON) → 送修正後的 items → 回傳新的驗證結果

Step 5: 確認匯入
  POST /import/confirm (JSON) → 送有效 items → 批次寫入 → 刷新列表
```

---

## API 規格

### 1. 匯出 Excel

```
GET /api/1.0/grc/project/<project_uid>/ap/<ap_uid>/jobs/export
Authorization: Bearer <token>
```

**Response:** 直接下載 `.xlsx` 檔案

**前端處理：**
```javascript
const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } })
const blob = await res.blob()
const a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = `job-setup.xlsx`
a.click()
```

**Excel 結構（10 欄，A 欄隱藏）：**

| 欄 | 標題 | 底色 | 可見 | 說明 |
|----|------|------|------|------|
| A | job_uid | 隱藏 | **隱藏** | 程式用，使用者看不到 |
| B | 控制項群組 | 灰底（唯讀） | 可見 | group name |
| C | 控制項識別碼 | 灰底（唯讀） | 可見 | e.g. `AC.L1-3.1.1` |
| D | 控制項名稱 | 灰底（唯讀） | 可見 | control title |
| E | 檢查項目名稱 | 灰底（唯讀） | 可見 | AO name |
| F | 任務名稱 | 灰底（唯讀） | 可見 | job name |
| G | 任務類型 | 淡黃底（**必填**） | 可見 | 下拉：`general` / `survey` |
| H | 指派人員 | 淡黃底（**必填**） | 可見 | 逗號分隔 login_name |
| I | 參與部門 | 淡黃底（選填） | 可見 | 逗號分隔部門名稱 |
| J | 設備 | 淡黃底（選填） | 可見 | 逗號分隔設備名稱 |

---

### 2. 匯入 Excel（上傳 + 驗證）

```
POST /api/1.0/grc/project/<project_uid>/ap/<ap_uid>/jobs/import
Authorization: Bearer <token>
Content-Type: multipart/form-data

file: <.xlsx，上限 10MB>
```

**Response：**

```json
{
  "status": true,
  "data": {
    "valid_count": 30,
    "error_count": 2,
    "items": [
      {
        "row": 2,
        "job_uid": "uuid-string",
        "job_name": "佐證文件上傳",
        "control_name": "授權存取控制",
        "ao_name": "[a] authorized users are identified",
        "job_type": "general",
        "assignees": "user1, user2",
        "departments": "資訊部",
        "devices": "Server-01",
        "errors": []
      },
      {
        "row": 5,
        "job_uid": "uuid-string",
        "job_name": "問卷填答",
        "control_name": "身份識別",
        "ao_name": "[a] identify system users",
        "job_type": "invalid",
        "assignees": "unknown_user",
        "departments": "",
        "devices": "",
        "errors": [
          {"field": "job_type", "message": "無效的任務類型，允許值：general, survey"},
          {"field": "assignees", "message": "使用者不存在：unknown_user"}
        ]
      }
    ]
  }
}
```

**欄位說明：**

| 欄位 | 說明 | 前端用途 |
|------|------|---------|
| `row` | Excel 行號 | 顯示錯誤位置 |
| `job_uid` | Job 內部 ID | **不要顯示**，validate/confirm 時原封帶回 |
| `job_name` | 任務名稱 | 表格顯示 |
| `control_name` | 控制項名稱 | 表格顯示 |
| `ao_name` | 檢查項目名稱 | 表格顯示 |
| `job_type` | 任務類型 | 表格顯示，可編輯 |
| `assignees` | 指派人員（逗號分隔） | 表格顯示，可編輯 |
| `departments` | 參與部門（逗號分隔） | 表格顯示，可編輯 |
| `devices` | 設備（逗號分隔） | 表格顯示，可編輯 |
| `errors` | 驗證錯誤清單 | 空陣列=有效，有值=有錯 |

---

### 3. 重新驗證（JSON）

使用者在前端表格修正錯誤後，送修正後的 items 重新驗證，不需重新上傳 Excel。

```
POST /api/1.0/grc/project/<project_uid>/ap/<ap_uid>/jobs/import/validate
Authorization: Bearer <token>
Content-Type: application/json
```

**Request Body：** 與 `/import/confirm` 相同格式

```json
{
  "items": [
    {
      "job_uid": "uuid-string",
      "job_type": "general",
      "assignees": "user1, corrected_user",
      "departments": "資訊部",
      "devices": "Server-01"
    },
    {
      "job_uid": "uuid-string-2",
      "job_type": "survey",
      "assignees": "user3",
      "departments": "",
      "devices": ""
    }
  ]
}
```

**Response：** 與 `POST /import`（上傳 Excel）完全相同格式

```json
{
  "status": true,
  "data": {
    "valid_count": 2,
    "error_count": 0,
    "items": [
      {
        "job_uid": "uuid-string",
        "job_type": "general",
        "assignees": "user1, corrected_user",
        "departments": "資訊部",
        "devices": "Server-01",
        "errors": []
      },
      {
        "job_uid": "uuid-string-2",
        "job_type": "survey",
        "assignees": "user3",
        "departments": "",
        "devices": "",
        "errors": []
      }
    ]
  }
}
```

---

### 4. 確認匯入（批次寫入）

需要 **manager 角色**才能執行。

```
POST /api/1.0/grc/project/<project_uid>/ap/<ap_uid>/jobs/import/confirm
Authorization: Bearer <token>
Content-Type: application/json
```

**Request Body：** 將驗證結果中 **errors 為空的項目** 原封送回。

```json
{
  "items": [
    {
      "job_uid": "uuid-string",
      "job_type": "general",
      "assignees": "user1, user2",
      "departments": "資訊部",
      "devices": "Server-01"
    }
  ]
}
```

**Response：**

```json
{
  "status": true,
  "data": {
    "updated_count": 30
  }
}
```

---

## 前端 UI 建議

### 按鈕位置
放在 Task Setup 頁面（任務設置樹狀結構頁面）的工具列：
- 「匯出 Excel」→ 點擊直接下載
- 「匯入 Excel」→ 點擊開啟 Dialog

### 匯入 Dialog 設計

**Step 1 — 上傳檔案**
- 拖拽或選擇 `.xlsx` 檔案
- 上傳後顯示 loading

**Step 2 — 驗證結果預覽（支援編輯 + 重新驗證）**
- 頂部摘要：`有效 30 筆 / 錯誤 2 筆`
- 表格欄位：

| 行號 | 控制項 | 檢查項目 | 任務名稱 | 任務類型 | 指派人員 | 部門 | 設備 | 狀態 |
|------|--------|---------|---------|---------|---------|------|------|------|
| 2 | AC.L1-3.1.1 授權存取控制 | [a] authorized users... | 佐證上傳 | general | user1, user2 | 資訊部 | Server-01 | ✓ |
| 5 | IA.L1-3.5.1 身份識別 | [a] identify... | 問卷填答 | ~~invalid~~ | ~~unknown_user~~ | | | ✗ |

- 名稱顯示：`control_name`、`ao_name`、`job_name`
- 錯誤行標紅，hover 顯示 `errors[].message`
- **可編輯欄位**（錯誤行允許直接修改）：

| 欄位 | 可編輯 | 輸入方式 |
|------|--------|---------|
| `job_type` | 是 | 下拉：general / survey |
| `assignees` | 是 | 文字輸入（逗號分隔 login_name） |
| `departments` | 是 | 文字輸入（逗號分隔部門名稱） |
| `devices` | 是 | 文字輸入（逗號分隔設備名稱） |
| `job_uid`、`job_name`、`control_name`、`ao_name` | 否 | 唯讀顯示 |

**Step 3 — 重新驗證**
- 「重新驗證」按鈕：表格有被編輯時 enable
- 點擊 → 收集所有 items → `POST /import/validate` → 更新表格與摘要
- 可重複多次直到全部有效

**Step 4 — 確認匯入**
- 按鈕：「匯入有效資料（N 筆）」/「取消」
- 過濾 `errors.length === 0` 的 items → `POST /import/confirm`
- 成功後顯示 `已更新 N 筆任務`
- 關閉 Dialog → 刷新 Task Setup 頁面

### 錯誤處理

| HTTP Status | 錯誤碼 | 情境 | 前端處理 |
|-------------|--------|------|---------|
| 400 | `GRC_400003` | 檔案格式無效 | 提示「請使用匯出的 Excel 範本」 |
| 400 | `GRC_400004` | 檔案超過 10MB | 提示「檔案大小超過限制」 |
| 403 | `GRC_403002` | 非 manager 角色（confirm 時） | 提示「需要管理者角色」 |
| 404 | `GRC_404006` | AP 不存在或無 Job | 提示錯誤 |

---

## API 總覽

| Method | URL | 說明 |
|--------|-----|------|
| GET | `/api/1.0/grc/project/<pid>/ap/<apid>/jobs/export` | 匯出 Excel |
| POST | `/api/1.0/grc/project/<pid>/ap/<apid>/jobs/import` | 上傳 Excel + 驗證 |
| POST | `/api/1.0/grc/project/<pid>/ap/<apid>/jobs/import/validate` | JSON 重新驗證 |
| POST | `/api/1.0/grc/project/<pid>/ap/<apid>/jobs/import/confirm` | 確認匯入（需 manager） |
