# 画面設計書 20-ロール新規登録

## 概要

本ドキュメントは、RuoYi後台管理システムにおけるロール新規登録画面の設計仕様を定義するものである。

### 本画面の処理概要

ロール新規登録画面は、システムに新しいロール（役割）を追加するためのモーダルダイアログ形式の画面である。ロールの基本情報（名前、権限文字、表示順、状態、備考）と、そのロールに割り当てるメニュー権限をzTreeで選択して登録する。

**業務上の目的・背景**：RBAC（Role-Based Access Control）の実装において、新しい役割グループを作成する際に使用する。ロールにはメニュー権限（機能へのアクセス権）が紐付けられ、このロールをユーザーに割り当てることで権限制御を実現する。

**画面へのアクセス方法**：ロール管理一覧画面（No.19）の「新增」ボタンをクリックするとモーダルダイアログとして表示される。URLパターンは `/system/role/add` である。

**主要な操作・処理内容**：
1. ロール名の入力（重複チェックあり）
2. 権限文字（roleKey）の入力（重複チェックあり）
3. 表示順の入力
4. 状態のトグル設定
5. 備考の入力
6. メニュー権限のツリー選択（展開/折りたたみ、全選択、父子連動）
7. 保存ボタンでロール登録

**画面遷移**：
- 遷移元：ロール管理一覧画面（No.19）
- 遷移先：なし（保存後はモーダルを閉じて一覧画面に戻る）

**権限による表示制御**：system:role:add権限が必要

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | ロール管理 | 主機能 | ロールの新規登録 |
| 5 | メニュー管理 | 補助機能 | メニュー権限ツリー取得 |

## 画面種別

登録（モーダルダイアログ形式・ツリー選択UI）

## URL/ルーティング

| メソッド | URL | 説明 |
|---------|-----|------|
| GET | /system/role/add | ロール新規登録画面表示 |
| POST | /system/role/add | ロール新規登録保存 |
| POST | /system/role/checkRoleNameUnique | ロール名重複チェック |
| POST | /system/role/checkRoleKeyUnique | 権限文字重複チェック |
| GET | /system/menu/roleMenuTreeData | メニューツリーデータ取得 |

## 入出力項目

### 入力項目

| No | 項目名 | 物理名 | 型 | 桁数 | 必須 | 初期値 | バリデーション |
|----|--------|--------|----|----|------|--------|--------------|
| 1 | 角色名称 | roleName | text | - | ○ | - | 必須、リモート重複チェック |
| 2 | 权限字符 | roleKey | text | - | ○ | - | 必須、リモート重複チェック |
| 3 | 显示顺序 | roleSort | number | - | ○ | - | 必須、数値のみ |
| 4 | 状态 | status | checkbox | - | - | 0（正常） | トグルスイッチ |
| 5 | 备注 | remark | text | - | - | - | - |
| 6 | 菜单权限 | menuIds | array | - | - | - | ツリー選択値 |

## 表示項目

| No | 項目名 | 説明 |
|----|--------|------|
| 1 | 展开/折叠チェックボックス | メニューツリーの展開/折りたたみ制御 |
| 2 | 全选/全不选チェックボックス | 全メニューの選択/解除 |
| 3 | 父子联动チェックボックス | 親子ノード連動の有効/無効（初期：有効） |
| 4 | メニューツリー | メニュー階層をzTreeで表示 |

## イベント仕様

### 1-画面初期表示

| 項目 | 内容 |
|------|------|
| トリガー | モーダルダイアログ表示時 |
| 処理内容 | 1. 入力フォームを空で表示<br>2. 状態トグルをON（有効）に設定<br>3. 父子联动チェックをONに設定<br>4. メニューツリーを初期化（Ajax取得）<br>5. expandLevel: 0で全ノード折りたたみ |
| 呼び出しAPI | GET /system/role/add, GET /system/menu/roleMenuTreeData |
| 遷移先 | - |

### 2-ロール名入力時（リモートバリデーション）

| 項目 | 内容 |
|------|------|
| トリガー | ロール名入力欄からフォーカスアウト時 |
| 処理内容 | 1. Ajaxでロール名をサーバーに送信<br>2. roleService.checkRoleNameUnique()で重複チェック<br>3. 重複時「角色名称已经存在」を表示 |
| 呼び出しAPI | POST /system/role/checkRoleNameUnique |
| 遷移先 | - |

### 3-権限文字入力時（リモートバリデーション）

| 項目 | 内容 |
|------|------|
| トリガー | 権限文字入力欄からフォーカスアウト時 |
| 処理内容 | 1. Ajaxで権限文字をサーバーに送信<br>2. roleService.checkRoleKeyUnique()で重複チェック<br>3. 重複時「角色权限已经存在」を表示 |
| 呼び出しAPI | POST /system/role/checkRoleKeyUnique |
| 遷移先 | - |

### 4-展開/折りたたみチェックボックス

| 項目 | 内容 |
|------|------|
| トリガー | 「展开/折叠」チェックボックス変更時 |
| 処理内容 | チェック時: $._tree.expandAll(true)<br>未チェック時: $._tree.expandAll(false) |
| 呼び出しAPI | - |
| 遷移先 | - |

### 5-全選択チェックボックス

| 項目 | 内容 |
|------|------|
| トリガー | 「全选/全不选」チェックボックス変更時 |
| 処理内容 | チェック時: $._tree.checkAllNodes(true)<br>未チェック時: $._tree.checkAllNodes(false) |
| 呼び出しAPI | - |
| 遷移先 | - |

### 6-父子連動チェックボックス

| 項目 | 内容 |
|------|------|
| トリガー | 「父子联动」チェックボックス変更時 |
| 処理内容 | チェック時: chkboxType = { "Y": "ps", "N": "ps" }（親子連動）<br>未チェック時: chkboxType = { "Y": "", "N": "" }（個別選択） |
| 呼び出しAPI | - |
| 遷移先 | - |

### 7-保存ボタン押下（submitHandler）

| 項目 | 内容 |
|------|------|
| トリガー | ダイアログの「確定」ボタン押下時 |
| 処理内容 | 1. フォームバリデーション実行<br>2. 各入力値を取得（roleName, roleKey, roleSort, status, remark）<br>3. statusはトグル状態から変換（checked→0, unchecked→1）<br>4. $.tree.getCheckedNodes()でmenuIdsを取得<br>5. Ajax POSTでロール登録<br>6. 成功時、権限キャッシュをクリア<br>7. モーダルを閉じて一覧をリロード |
| 呼び出しAPI | POST /system/role/add |
| 遷移先 | ロール管理一覧画面 |

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | sys_role | INSERT | ロールマスタ登録 |
| 保存ボタン押下 | sys_role_menu | INSERT | ロール-メニュー関連登録 |

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

#### sys_role

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | role_name | 入力値 | ロール名 |
| INSERT | role_key | 入力値 | 権限文字（@RequiresRolesで使用） |
| INSERT | role_sort | 入力値 | 表示順 |
| INSERT | status | 0 or 1 | 0:正常, 1:停用 |
| INSERT | remark | 入力値 | 備考 |
| INSERT | create_by | ログインユーザー | 作成者 |
| INSERT | create_time | 現在日時 | 作成日時 |

#### sys_role_menu

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | role_id | 新規ロールID | 自動採番 |
| INSERT | menu_id | menuIds配列の各値 | 選択されたメニューID |

## メッセージ仕様

| No | 種別 | メッセージ | 表示条件 |
|----|------|----------|----------|
| 1 | 成功 | 操作成功 | ロール登録成功時 |
| 2 | エラー | 角色名称已经存在 | ロール名重複時 |
| 3 | エラー | 角色权限已经存在 | 権限文字重複時 |
| 4 | エラー | 系统错误 | Ajax通信エラー時 |
| 5 | エラー | 新增角色'xxx'失败，角色名称已存在 | サーバー側重複検知時 |
| 6 | エラー | 新增角色'xxx'失败，角色权限已存在 | サーバー側重複検知時 |

## 例外処理

| 例外パターン | 対応処理 |
|------------|---------|
| ロール名重複 | リモートバリデーションでエラー表示 |
| 権限文字重複 | リモートバリデーションでエラー表示 |
| 表示順非数値 | digits バリデーションでエラー表示 |
| Ajax通信エラー | 「系统错误」を表示 |

## 備考

- roleKeyは@RequiresRoles("")アノテーションで使用される権限文字列
- 父子联动はzTreeのchkboxType設定で制御
- 登録成功後、AuthorizationUtils.clearAllCachedAuthorizationInfo()でShiro権限キャッシュをクリア
- メニューツリーはexpandLevel: 0で初期状態は全て折りたたみ

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysRoleController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java` | add()（GET/POST）、checkRoleNameUnique()、checkRoleKeyUnique()メソッド |

**主要処理フロー**:
1. **80-85行目**: `add()` GET - 画面表示
2. **90-107行目**: `addSave()` POST - ロール登録処理
3. **189-193行目**: `checkRoleNameUnique()` - ロール名重複チェック
4. **199-203行目**: `checkRoleKeyUnique()` - 権限文字重複チェック

#### Step 2: 画面テンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | add.html | `ruoyi-admin/src/main/resources/templates/system/role/add.html` | フォーム、zTree初期化、バリデーション |

**主要処理フロー**:
- **10-15行目**: ロール名入力（required）
- **17-22行目**: 権限文字入力（ヘルプテキスト付き）
- **24-28行目**: 表示順入力
- **30-37行目**: 状態トグル
- **39-42行目**: 備考入力
- **44-55行目**: メニューツリーエリア（展開/全選択/父子連動チェック）
- **61-69行目**: zTree初期化（check: { enable: true }）
- **72-112行目**: jQueryValidateルール（リモートバリデーション）
- **114-136行目**: チェックボックスイベント（ifChanged）
- **138-171行目**: submitHandler()とadd()関数

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

```
ロール管理一覧 [新增]ボタン
    │
    └─ $.operate.add()
           │
           └─ SysRoleController.add() GET       ← GET /system/role/add
                  │
                  └─ add.html 表示
                         │
                         ├─ $.tree.init()
                         │      └─ Ajax → /system/menu/roleMenuTreeData
                         │             └─ SysMenuController.roleMenuTreeData()
                         │
                         ├─ [角色名称] フォーカスアウト
                         │      └─ Ajax → SysRoleController.checkRoleNameUnique()
                         │             └─ roleService.checkRoleNameUnique()
                         │
                         ├─ [权限字符] フォーカスアウト
                         │      └─ Ajax → SysRoleController.checkRoleKeyUnique()
                         │             └─ roleService.checkRoleKeyUnique()
                         │
                         ├─ [展开/折叠] チェック → $._tree.expandAll()
                         │
                         ├─ [全选/全不选] チェック → $._tree.checkAllNodes()
                         │
                         ├─ [父子联动] チェック → chkboxType設定変更
                         │
                         └─ [確定]ボタン
                                │
                                ├─ $.validate.form()
                                ├─ $.tree.getCheckedNodes()  ← menuIds取得
                                │
                                └─ Ajax POST → SysRoleController.addSave()
                                       ├─ checkRoleNameUnique()  ← 再検証
                                       ├─ checkRoleKeyUnique()   ← 再検証
                                       ├─ roleService.insertRole()
                                       │      ├─ sys_role INSERT
                                       │      └─ sys_role_menu INSERT（複数）
                                       └─ clearAllCachedAuthorizationInfo()
```

### データフロー図

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

roleName         SysRoleController.checkRoleNameUnique()
     │                   │
     └─────────▶ roleService.checkRoleNameUnique()  ─▶ true/false

roleKey          SysRoleController.checkRoleKeyUnique()
     │                   │
     └─────────▶ roleService.checkRoleKeyUnique()   ─▶ true/false

フォームデータ           SysRoleController.addSave()
(roleName,              │
roleKey,                ├─ @Validated SysRole
roleSort,               │
status,                 ├─ roleService.insertRole()
remark,                 │      │
menuIds)                │      ├─ sys_role INSERT
     │                  │      │
     └─────────▶        │      └─ sys_role_menu INSERT (loop)
                        │
                        └─ clearAllCachedAuthorizationInfo() ─▶ キャッシュクリア
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SysRoleController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java` | コントローラー | add(), addSave(), checkXxxUnique()メソッド |
| add.html | `ruoyi-admin/src/main/resources/templates/system/role/add.html` | テンプレート | ロール新規登録フォーム |
| SysMenuController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java` | コントローラー | roleMenuTreeData()メソッド |
| ISysRoleService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java` | インターフェース | insertRole(), checkRoleNameUnique(), checkRoleKeyUnique() |
| SysRoleServiceImpl.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java` | サービス実装 | ロール登録処理実装 |
| SysRoleMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml` | Mapper | insertRole SQL |
| SysRoleMenuMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml` | Mapper | batchRoleMenu SQL |
| SysRole.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java` | エンティティ | menuIds（Long[]）フィールド含む |
| AuthorizationUtils.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/util/AuthorizationUtils.java` | ユーティリティ | clearAllCachedAuthorizationInfo() |
