# 画面設計書 13-チーム別会話一覧

## 概要

本ドキュメントは、Chatwootのチーム別会話一覧画面の設計仕様を記述したものです。特定のチームに割り当てられた会話のみを表示する、フィルタリングされた会話一覧画面です。

### 本画面の処理概要

**業務上の目的・背景**：
組織内で複数のチーム（例：「営業チーム」「技術サポートチーム」「請求チーム」など）が存在する場合、各チームは自分たちに関連する会話だけを効率的に処理する必要があります。チーム別会話一覧は、チームメンバーが自チームに割り当てられた会話を一元的に管理し、チーム内での効率的な業務分担を実現します。

**画面へのアクセス方法**：
1. サイドバーのチーム一覧から特定のチームをクリック
2. URL直接アクセス: `/app/accounts/:accountId/team/:teamId`

**主要な操作・処理内容**：
1. チームでフィルタリングされた会話一覧の表示
2. 担当者タブ（自分/未割り当て/すべて）による追加フィルタリング
3. ステータスフィルター（Open/Resolved/Pending/Snoozed）による絞り込み
4. 会話の選択と詳細表示
5. 一括操作（複数会話のステータス変更、割り当て変更など）
6. 会話の検索
7. 高度なフィルター機能

**画面遷移**：
- 遷移元: ダッシュボードホーム画面（サイドバーのチームリンク）
- 遷移先: 会話詳細画面（会話クリック時）

**権限による表示制御**：
- administrator: 全機能へのフルアクセス
- agent: 基本的な会話閲覧・操作（所属チームの会話のみ）
- conversation_manage: 会話の管理操作が可能
- conversation_unassigned_manage: 未割り当て会話タブの表示
- conversation_participating_manage: 参加中会話の管理

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 会話CRUD | 主機能 | 特定チームの会話一覧表示 |
| 13 | チーム管理 | 補助機能 | チームIDによるフィルタリング |

## 画面種別

一覧

## URL/ルーティング

| ルート名 | パス | 説明 |
|---------|------|------|
| team_conversations | `/accounts/:accountId/team/:teamId` | チーム別会話一覧（詳細なし） |
| conversations_through_team | `/accounts/:accountId/team/:teamId/conversations/:conversationId` | チーム別会話一覧（詳細あり） |

## 入出力項目

### ルートパラメータ

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| accountId | Number | Yes | アカウントID |
| teamId | String | Yes | フィルタリング対象のチームID |
| conversationId | Number | No | 表示する会話ID（詳細表示時） |

### コンポーネントProps

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| teamId | String | Yes | フィルタリング用チームID |
| conversationId | String/Number | No | 選択中の会話ID |

## 表示項目

### ヘッダー部

| 項目名 | 型 | 説明 |
|--------|-----|------|
| page_title | String | チーム名（getTeamから取得） |
| conversation_count | Number | フィルタリング結果の会話数 |
| filter_button | Button | 高度なフィルターモーダル表示ボタン |

### 会話一覧

| 項目名 | 型 | 説明 |
|--------|-----|------|
| conversation_card | Component | 会話カード（ConversationItem） |
| inbox_icon | Icon | インボックスのアイコン |
| contact_name | String | 連絡先名 |
| last_message_preview | String | 最新メッセージのプレビュー |
| last_activity_time | DateTime | 最終活動時刻 |
| unread_count | Number | 未読メッセージ数 |
| labels | Array | 付与されているラベル一覧 |
| assignee_avatar | Image | 担当者アバター |

### 担当者タブ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| me_tab | Tab | 自分に割り当てられた会話 |
| unassigned_tab | Tab | 未割り当ての会話 |
| all_tab | Tab | すべての会話 |
| tab_count | Number | 各タブの会話数 |

## イベント仕様

### 1-チーム切り替え

**トリガー**: サイドバーで別のチームをクリック

**処理フロー**:
1. Vue Routerでルートパラメータ変更を検知
2. ChatList.vueのwatchでactiveTeamの変更を検知
3. resetAndFetchData()を呼び出し
4. 会話リストをクリアしてAPIから再取得
5. 新しいチームでフィルタリングされた会話を表示

**Vuexアクション**: `fetchAllConversations`

### 2-会話選択

**トリガー**: 会話カードのクリック

**処理フロー**:
1. ConversationItemコンポーネントでクリックイベント発火
2. Vue Routerで`conversations_through_team`ルートへ遷移
3. ConversationView.vueのpropsが更新
4. setActiveChat()で選択会話をストアに設定
5. ConversationBox.vueで会話詳細を表示

### 3-担当者タブ切り替え

**トリガー**: 担当者タブのクリック

**処理フロー**:
1. ChatTypeTabs.vueでタブ選択イベント発火
2. activeAssigneeTabの更新
3. conversationFiltersの再計算
4. 必要に応じてfetchConversations()実行

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 会話一覧取得 | conversations | SELECT | チームIDでフィルタリングした会話取得 |
| チーム情報取得 | teams | SELECT | チーム名の取得 |

### テーブル別更新項目詳細

#### conversations（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | team_id = :teamId | APIでteam_idを指定 |
| SELECT | status | フィルター条件 | ステータスフィルター |
| SELECT | assignee_id | フィルター条件 | 担当者フィルター |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| CHAT_LIST.LIST.404 | 情報 | 会話が見つかりません | フィルタリング結果が0件 |
| CHAT_LIST.EOF | 情報 | すべての会話を表示しました | リスト末尾到達時 |

## 例外処理

| 例外状態 | 表示内容 | 処理 |
|---------|---------|------|
| チームが存在しない | 空の会話一覧 | 404は表示せず空状態を表示 |
| 会話が0件 | 「会話が見つかりません」メッセージ | |
| ネットワークエラー | ローディング継続または再試行 | |

## 備考

- チーム情報はVuexのteamsモジュールから取得（getTeam getter使用）
- チームに所属していないエージェントはこの画面にアクセスできない場合がある
- チーム名がページタイトルとして表示される

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conversation.routes.js | `app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js` | 行87-109でチーム関連ルートを確認 |

**読解のコツ**: teamId propsがどのようにルートパラメータから渡されるかを確認してください。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ConversationView.vue | `app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue` | 行43-46でteamId propsの定義を確認 |

**主要処理フロー**:
1. **行43-46**: teamId propsの定義（デフォルト空文字列）
2. **行199-208**: ChatListへのteam-id propsの受け渡し

#### Step 3: フィルタリングロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ChatList.vue | `app/javascript/dashboard/components/ChatList.vue` | teamIdによるフィルタリング処理 |

**主要処理フロー**:
- **行79**: teamId propsの定義
- **行277-288**: conversationFiltersでteamIdをフィルター条件に含める
- **行290-295**: activeTeamでチーム情報を取得
- **行303-306**: pageTitleでチーム名を表示
- **行870**: watch(activeTeam)で変更時にresetAndFetchData()呼び出し

### プログラム呼び出し階層図

```
ConversationView.vue
    |
    +-- ChatList.vue (teamId props受け渡し)
    |       |
    |       +-- activeTeam (computed)
    |       |       getTeamFn(teamId)
    |       |
    |       +-- conversationFilters (computed)
    |       |       teamId: props.teamId
    |       |
    |       +-- fetchConversations()
    |               |
    |               +-- ConversationApi.get({ team_id: teamId })
    |
    +-- ConversationBox.vue (選択時)
```

### データフロー図

```
[入力]                   [処理]                        [出力]

URL params          --> Vue Router                --> ConversationView.vue
(/team/:teamId)         (route matching)              (teamId props)
                                                          |
                                                          v
                    --> ChatList.vue              --> conversationFilters
                        (teamId props)                ({ teamId: teamId })
                                                          |
                                                          v
                    --> Vuex teams/getTeam        --> activeTeam
                        (teamId)                      (チーム情報取得)
                                                          |
                                                          v
                    --> ConversationApi.get()     --> API Request
                        ({ team_id: teamId })         (GET /conversations?team_id=teamId)
                                                          |
                                                          v
                    --> Vuex Store                --> 会話一覧表示
                        (allConversations)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ConversationView.vue | `app/javascript/dashboard/routes/dashboard/conversation/ConversationView.vue` | ソース | ルートコンポーネント |
| conversation.routes.js | `app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js` | ソース | チームルート定義 |
| ChatList.vue | `app/javascript/dashboard/components/ChatList.vue` | ソース | 会話一覧・フィルタリング |
| conversation.js | `app/javascript/dashboard/api/inbox/conversation.js` | ソース | API（team_id パラメータ対応） |
| teams/getters.js | `app/javascript/dashboard/store/modules/teams/getters.js` | ソース | チーム情報取得 |
