# 画面設計書 21-ロール編集

## 概要

本ドキュメントは、RuoYi後台管理システムにおける「ロール編集」画面の設計仕様を定義するものである。既存のロール情報を編集・更新するための画面で、ロール名、権限字符、表示順序、状態、メニュー権限などの設定変更が可能である。

### 本画面の処理概要

この画面では、システムに登録されている既存のロール情報を編集し、変更内容をデータベースに保存する処理を行う。ロール編集はシステムの権限管理において重要な機能であり、誤った設定により権限の過剰付与や不足が発生しないよう、慎重な運用が求められる。

**業務上の目的・背景**：組織の変更や業務プロセスの見直しに伴い、既存ロールの権限範囲やメニューアクセス権を変更する必要がある。この画面により、管理者はシステム全体のアクセス制御を柔軟に調整でき、セキュリティポリシーの維持と業務効率の両立を実現する。

**画面へのアクセス方法**：ロール管理一覧画面から対象ロールの「編集」ボタンをクリック、またはロールを選択してツールバーの「修正」ボタンをクリックすることで、モーダルダイアログとして表示される。

**主要な操作・処理内容**：
1. ロール名称の変更（必須、30文字以内、重複不可）
2. 権限字符（roleKey）の変更（必須、100文字以内、重複不可）
3. 表示順序の変更（数字のみ）
4. ステータスの切り替え（有効/無効）
5. 備考の編集
6. メニュー権限のツリー選択（展開/折叠、全選択/全解除、親子連動機能付き）
7. 変更内容の保存

**画面遷移**：ロール管理一覧画面から遷移し、保存完了後は一覧画面に戻る。キャンセル時も一覧画面に戻る。

**権限による表示制御**：`system:role:edit`権限を持つユーザーのみアクセス可能。管理者ロール（roleId=1）は編集操作が制限される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | ロール管理 | 主機能 | ロール情報の更新保存処理 |
| 3 | メニュー管理 | 補助機能 | メニュー権限ツリーの取得処理 |

## 画面種別

編集（モーダルダイアログ）

## URL/ルーティング

- 画面表示: `GET /system/role/edit/{roleId}`
- データ保存: `POST /system/role/edit`
- ロール名重複チェック: `POST /system/role/checkRoleNameUnique`
- 権限字符重複チェック: `POST /system/role/checkRoleKeyUnique`
- メニューツリーデータ: `GET /system/menu/roleMenuTreeData?roleId={roleId}`

## 入出力項目

### 入力項目

| 項目名 | 物理名 | 型 | 必須 | 最大長 | バリデーション | 説明 |
|--------|--------|-----|------|--------|----------------|------|
| ロールID | roleId | Long | - | - | 自動（hidden） | 編集対象のロールID |
| ロール名称 | roleName | String | 必須 | 30 | 重複チェック、空白不可 | ロールの表示名 |
| 権限字符 | roleKey | String | 必須 | 100 | 重複チェック、空白不可 | @RequiresRolesで使用する識別子 |
| 表示順序 | roleSort | String | 必須 | - | 数字のみ | ロール一覧での表示順 |
| 状態 | status | String | - | 1 | 0:有効、1:無効 | ロールの有効/無効状態 |
| 備考 | remark | String | - | 500 | - | ロールの補足説明 |
| メニューID配列 | menuIds | Long[] | - | - | - | 割り当てるメニューのID配列 |

### 出力項目（初期表示）

| 項目名 | 物理名 | 型 | 説明 |
|--------|--------|-----|------|
| ロール情報 | role | SysRole | 編集対象のロール情報 |
| メニューツリー | menuTrees | List<Ztree> | 選択済みメニューを含むツリーデータ |

## 表示項目

| 表示項目 | 説明 | 初期値 |
|----------|------|--------|
| ロール名称入力欄 | テキスト入力 | DBから取得した値 |
| 権限字符入力欄 | テキスト入力 + ヘルプテキスト | DBから取得した値 |
| 表示順序入力欄 | テキスト入力 | DBから取得した値 |
| 状態トグルスイッチ | ON/OFF切替 | DBの状態値に応じた表示 |
| 備考入力欄 | テキスト入力 | DBから取得した値 |
| 展開/折叠チェックボックス | ツリー展開制御 | 未チェック |
| 全選択/全解除チェックボックス | 一括選択制御 | 未チェック |
| 親子連動チェックボックス | 連動選択制御 | チェック済み |
| メニュー権限ツリー | zTreeによるチェックボックスツリー | 既存権限が選択された状態 |

## イベント仕様

### 1-画面表示

モーダルダイアログとしてロール編集画面を表示する。

**処理フロー**：
1. `SysRoleController.edit()`がroleIdを受け取る
2. `roleService.checkRoleDataScope()`でデータスコープ権限を検証
3. `roleService.selectRoleById()`でロール情報を取得
4. ModelMapにロール情報を設定
5. Thymeleafテンプレートを描画
6. JavaScript初期化処理でメニューツリーをAjax取得

### 2-ロール名重複チェック（リアルタイム）

入力完了時にロール名の重複をチェックする。

**処理フロー**：
1. フォームバリデーションでremoteルールが発火
2. `POST /system/role/checkRoleNameUnique`を呼び出し
3. roleIdとroleNameをパラメータとして送信
4. 重複時はエラーメッセージ「角色名称已经存在」を表示

### 3-権限字符重複チェック（リアルタイム）

入力完了時に権限字符の重複をチェックする。

**処理フロー**：
1. フォームバリデーションでremoteルールが発火
2. `POST /system/role/checkRoleKeyUnique`を呼び出し
3. roleIdとroleKeyをパラメータとして送信
4. 重複時はエラーメッセージ「角色权限已经存在」を表示

### 4-ツリー展開/折叠

メニューツリーの展開/折叠を切り替える。

**処理フロー**：
1. チェックボックスの変更イベントを検知
2. チェック時: `$._tree.expandAll(true)`で全展開
3. 未チェック時: `$._tree.expandAll(false)`で全折叠

### 5-全選択/全解除

メニューツリーの全選択/全解除を切り替える。

**処理フロー**：
1. チェックボックスの変更イベントを検知
2. チェック時: `$._tree.checkAllNodes(true)`で全選択
3. 未チェック時: `$._tree.checkAllNodes(false)`で全解除

### 6-親子連動切替

親子ノードの連動選択を切り替える。

**処理フロー**：
1. チェックボックスの変更イベントを検知
2. チェック時: `chkboxType = { "Y": "ps", "N": "ps" }`で連動有効
3. 未チェック時: `chkboxType = { "Y": "", "N": "" }`で連動無効

### 7-保存ボタン押下

編集内容をサーバーに送信して保存する。

**処理フロー**：
1. `submitHandler()`関数が呼び出される
2. `$.validate.form()`でクライアントバリデーション実行
3. バリデーション成功時、`edit()`関数を呼び出し
4. 選択されたメニューIDを`$.tree.getCheckedNodes()`で取得
5. Ajax POSTでサーバーに送信
6. サーバー側で`checkRoleAllowed()`、`checkRoleDataScope()`を実行
7. 重複チェック実行
8. `roleService.updateRole()`でDB更新
9. 成功時はモーダルを閉じて一覧を更新

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | sys_role | UPDATE | ロール基本情報の更新 |
| 保存ボタン押下 | sys_role_menu | DELETE | 既存のロール-メニュー関連を全削除 |
| 保存ボタン押下 | sys_role_menu | INSERT | 新規のロール-メニュー関連を登録 |

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

#### sys_role

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | role_name | 入力値 | ロール名称 |
| UPDATE | role_key | 入力値 | 権限字符 |
| UPDATE | role_sort | 入力値 | 表示順序 |
| UPDATE | status | 入力値（0または1） | 状態 |
| UPDATE | remark | 入力値 | 備考 |
| UPDATE | update_by | ログインユーザー名 | 更新者 |
| UPDATE | update_time | sysdate() | 更新日時 |

#### sys_role_menu

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | role_id = 対象ロールID | 既存関連を削除 |
| INSERT | role_id | 対象ロールID | ロールID |
| INSERT | menu_id | 選択されたメニューID | メニューID |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|----------|
| エラー | 角色名称已经存在 | ロール名が重複している場合 |
| エラー | 角色权限已经存在 | 権限字符が重複している場合 |
| エラー | 修改角色'{roleName}'失败，角色名称已存在 | 保存時にロール名重複 |
| エラー | 修改角色'{roleName}'失败，角色权限已存在 | 保存時に権限字符重複 |
| エラー | 系统错误 | 通信エラー発生時 |
| 成功 | 操作成功 | 保存成功時 |

## 例外処理

| 例外状況 | 処理内容 |
|----------|----------|
| データスコープ外のロール | ServiceExceptionをスローし、アクセス拒否 |
| 管理者ロール(roleId=1)の編集 | ServiceExceptionをスローし、操作拒否 |
| 通信エラー | 「系统错误」メッセージを表示 |
| セッションタイムアウト | ログイン画面へリダイレクト |
| バリデーションエラー | 該当項目にエラーメッセージを表示 |

## 備考

- 管理者ロール（roleId=1）は特別な保護対象であり、編集・削除が制限される
- メニュー権限の変更は即座にシステムに反映される（キャッシュクリア処理あり）
- 親子連動機能により、親メニューをチェックすると自動的に子メニューもチェックされる
- zTreeライブラリを使用してメニュー権限ツリーを表示

---

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

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

### 推奨読解順序

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

まず、プログラム間で受け渡されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysRole.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java` | ロールエンティティの構造、menuIds/deptIds配列の用途を理解する |
| 1-2 | Ztree.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/Ztree.java` | メニューツリー表示用のデータ構造を理解する |

**読解のコツ**: SysRoleクラスの`menuIds`配列はロール-メニュー関連テーブルへの登録用に使用される。`@NotBlank`等のバリデーションアノテーションにも注目する。

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

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SysRoleController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java` | edit()メソッドとeditSave()メソッドの処理フローを理解する |

**主要処理フロー**:
1. **113-119行目**: edit()メソッド - 編集画面表示処理、データスコープチェックとロール情報取得
2. **125-144行目**: editSave()メソッド - 保存処理、各種チェックと更新処理

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ISysRoleService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java` | ロールサービスのインターフェース定義 |
| 3-2 | SysRoleServiceImpl.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java` | updateRole()メソッドの実装詳細 |

**主要処理フロー**:
- updateRole(): ロール基本情報の更新 -> 既存メニュー関連の削除 -> 新規メニュー関連の登録

#### Step 4: データアクセス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SysRoleMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml` | updateRole SQLの詳細 |
| 4-2 | SysRoleMenuMapper.java | `ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java` | ロール-メニュー関連のCRUD操作 |

**主要処理フロー**:
- **95-108行目**: updateRole - ロール基本情報の更新SQL

#### Step 5: フロントエンド処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | edit.html | `ruoyi-admin/src/main/resources/templates/system/role/edit.html` | 画面構造とJavaScript処理を理解する |

**主要処理フロー**:
- **62-71行目**: メニューツリーの初期化処理
- **73-119行目**: バリデーション設定（重複チェック含む）
- **145-174行目**: edit()関数 - 保存処理のAjax呼び出し

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

```
[画面表示] edit.html
    │
    ├─ SysRoleController.edit()
    │      ├─ roleService.checkRoleDataScope()
    │      └─ roleService.selectRoleById()
    │
    ├─ [Ajax] roleMenuTreeData
    │      └─ SysMenuController.roleMenuTreeData()
    │             └─ menuService.roleMenuTreeData()
    │
    └─ [保存] edit()関数
           └─ SysRoleController.editSave()
                  ├─ roleService.checkRoleAllowed()
                  ├─ roleService.checkRoleDataScope()
                  ├─ roleService.checkRoleNameUnique()
                  ├─ roleService.checkRoleKeyUnique()
                  └─ roleService.updateRole()
                         ├─ SysRoleMapper.updateRole()
                         ├─ SysRoleMenuMapper.deleteRoleMenuByRoleId()
                         └─ SysRoleMenuMapper.batchRoleMenu()
```

### データフロー図

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

roleId(hidden) ─────┐
roleName ───────────┤
roleKey ────────────┤     SysRoleController.editSave()
roleSort ───────────┼───▶ SysRoleServiceImpl.updateRole() ───▶ sys_role (UPDATE)
status ─────────────┤           │                              sys_role_menu (DELETE/INSERT)
remark ─────────────┤           │
menuIds[] ──────────┘           ▼
                         AuthorizationUtils.clearAllCachedAuthorizationInfo()
                         (権限キャッシュクリア)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| edit.html | `ruoyi-admin/src/main/resources/templates/system/role/edit.html` | テンプレート | ロール編集画面のHTML/JavaScript |
| SysRoleController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java` | コントローラー | HTTPリクエストの処理 |
| ISysRoleService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java` | インターフェース | ロールサービスの定義 |
| SysRoleServiceImpl.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java` | サービス実装 | ビジネスロジック |
| SysRoleMapper.java | `ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java` | マッパー | データアクセス |
| SysRoleMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml` | SQL定義 | SQL文の定義 |
| SysRole.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java` | エンティティ | ロールデータモデル |
| ry.js | `ruoyi-admin/src/main/resources/static/ruoyi/js/ry.js` | JavaScript | 共通JavaScript関数 |
