# 画面設計書 17-参加中会話一覧

## 概要

本ドキュメントは、Chatwootの参加中会話一覧画面の設計仕様を記述したものです。現在のユーザーが参加者として追加されている会話を表示する画面です。

### 本画面の処理概要

**業務上の目的・背景**：
Chatwootでは、会話の担当者（Assignee）とは別に、複数のエージェントが会話の「参加者（Participant）」として関与できます。これは、複雑な問い合わせに対して複数のエージェントが協力して対応する場合や、エスカレーション時に上位のサポートスタッフを会話に追加する場合などに使用されます。参加中会話一覧は、自分が参加者として追加されている会話を一元的に確認できる画面です。

**画面へのアクセス方法**：
1. サイドバーの「Participating」リンクをクリック
2. URL直接アクセス: `/app/accounts/:accountId/participating/conversations`

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

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

**権限による表示制御**：
- administrator: 全機能へのフルアクセス
- agent: 自分が参加している会話の閲覧・操作
- conversation_manage: 会話の管理操作が可能
- conversation_unassigned_manage: 未割り当て会話タブの表示
- conversation_participating_manage: 参加中会話の管理

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | 会話CRUD | 主機能 | 参加中会話の一覧表示 |
| 31 | 参加者管理 | 補助機能 | 参加状態によるフィルタリング |

## 画面種別

一覧

## URL/ルーティング

| ルート名 | パス | 説明 |
|---------|------|------|
| conversation_participating | `/accounts/:accountId/participating/conversations` | 参加中会話一覧（詳細なし） |
| conversation_through_participating | `/accounts/:accountId/participating/conversations/:conversationId` | 参加中会話一覧（詳細あり） |

## 入出力項目

### ルートパラメータ

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| accountId | Number | Yes | アカウントID |
| conversationId | Number | No | 表示する会話ID（詳細表示時） |

### コンポーネントProps

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| conversationType | String | Yes | 'participating'固定 |
| conversationId | String/Number | No | 選択中の会話ID |

## 表示項目

### ヘッダー部

| 項目名 | 型 | 説明 |
|--------|-----|------|
| page_title | String | 「Participating」（i18n: CONVERSATION_PARTICIPANTS.SIDEBAR_MENU_TITLE） |
| 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 | 担当者アバター |
| participants_count | Number | 参加者数 |

### 担当者タブ

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

## イベント仕様

### 1-参加中一覧表示

**トリガー**: サイドバーの「Participating」リンクをクリック

**処理フロー**:
1. Vue Routerでconversation_participatingルートへ遷移
2. ConversationView.vueにconversationType='participating'がpropsとして渡される
3. ChatList.vueのconversationFiltersでconversationType: 'participating'が設定される
4. fetchConversations()でAPIリクエスト
5. サーバー側で参加者フィルタリングが適用された会話一覧を取得

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

### 2-会話選択

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

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

### 3-参加者追加/削除

**トリガー**: 会話詳細で参加者の追加/削除

**処理フロー**:
1. 会話詳細画面の参加者管理UIで操作
2. ConversationApi.updateParticipants()でサーバーへ送信
3. 自分が参加者から削除された場合、リストから会話が消える
4. 自分が追加された場合、リストに会話が追加される

**Vuexアクション**: 参加者更新関連アクション

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 参加中会話一覧取得 | conversations | SELECT | 参加中会話の取得 |
| 参加中会話一覧取得 | conversation_participants | SELECT | 参加者関係の取得 |

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

#### conversations（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | conversation_type = 'participating' | APIパラメータ |
| SELECT | status | フィルター条件 | ステータスフィルター |
| SELECT | assignee_id | フィルター条件 | 担当者フィルター |

#### conversation_participants（SELECT）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | user_id | 現在のユーザーID | 参加者確認 |

## メッセージ仕様

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

## 例外処理

| 例外状態 | 表示内容 | 処理 |
|---------|---------|------|
| 参加中会話が0件 | 「会話が見つかりません」メッセージ | |
| ネットワークエラー | ローディング継続または再試行 | |

## 備考

- 参加者は会話詳細画面のサイドバーから追加/削除できる
- 担当者（Assignee）と参加者（Participant）は別の概念
- 担当者でなくても参加者として会話にアクセスできる
- 参加者は会話内でプライベートノートを閲覧可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conversation.routes.js | `app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js` | 行179-202で参加中関連ルートを確認 |

**読解のコツ**: conversationType propsがどのように'participating'として渡されるかを確認してください。

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

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

**主要処理フロー**:
1. **行47-50**: conversationType propsの定義（デフォルト空文字列）
2. **行199-208**: ChatListへのconversation-type propsの受け渡し

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

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

**主要処理フロー**:
- **行79**: conversationType propsの定義
- **行277-288**: conversationFiltersでconversationTypeをフィルター条件に含める
- **行313-315**: pageTitleで「Participating」を表示
- **行880-883**: watch(conversationType)で変更時にresetAndFetchData()呼び出し

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

```
ConversationView.vue
    |
    +-- ChatList.vue (conversationType='participating' props受け渡し)
    |       |
    |       +-- conversationFilters (computed)
    |       |       conversationType: 'participating'
    |       |
    |       +-- pageTitle (computed)
    |       |       $t('CONVERSATION_PARTICIPANTS.SIDEBAR_MENU_TITLE')
    |       |
    |       +-- fetchConversations()
    |               |
    |               +-- ConversationApi.get({ conversation_type: 'participating' })
    |
    +-- ConversationBox.vue (選択時)
```

### データフロー図

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

URL params          --> Vue Router                --> ConversationView.vue
(/participating/...)    (route matching)              (conversationType='participating')
                                                          |
                                                          v
                    --> ChatList.vue              --> conversationFilters
                        (conversationType props)      ({ conversationType: 'participating' })
                                                          |
                                                          v
                    --> ConversationApi.get()     --> API Request
                        ({ conversation_type })       (GET /conversations?conversation_type=participating)
                                                          |
                                                          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（conversation_type、participants対応） |
