# 画面設計書 27-メニュー編集

## 概要

本ドキュメントは、RuoYi後台管理システムにおける「メニュー編集」画面の設計仕様を定義するものである。既存メニュー情報を修正するためのモーダルダイアログで、目録（ディレクトリ）、菜単（メニュー項目）、按鈕（ボタン/権限）の3種類のメニューを編集できる。

### 本画面の処理概要

この画面では、既存メニューの情報を編集してシステムに保存する。メニュー種別に応じて入力項目が動的に変化し、適切な設定を行える。親メニューの変更により階層構造を再構築できる。

**業務上の目的・背景**：業務要件の変更に伴い、既存メニューの名称や権限標識、表示順序などを変更する必要がある。この画面により、管理者はメニュー設定を柔軟に変更でき、システムの保守性を確保する。

**画面へのアクセス方法**：メニュー管理一覧画面の各行の「修改」リンクをクリックすることで、モーダルダイアログとして表示される。

**主要な操作・処理内容**：
1. 上級菜単の変更（メニューツリーダイアログ経由）
2. 菜単類型の変更（目録/菜単/按鈕）
3. 菜単名称の編集
4. 請求地址の編集（菜単タイプのみ）
5. 打開方式の変更（頁簽/新窗口）
6. 権限標識の編集
7. 顕示順序の編集
8. 図標（アイコン）の変更
9. 菜単状態・刷新設定の変更
10. 編集内容の保存

**画面遷移**：メニュー管理一覧画面からモーダルとして表示。保存成功時は自動でダイアログを閉じ、親画面を更新。

**権限による表示制御**：`system:menu:edit`権限を持つユーザーのみアクセス可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | メニュー管理 | 主機能 | 既存メニュー情報編集と更新保存処理 |

## 画面種別

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

## URL/ルーティング

- 画面表示: `GET /system/menu/edit/{menuId}`
- データ保存: `POST /system/menu/edit`
- メニュー名重複チェック: `POST /system/menu/checkMenuNameUnique`
- メニューツリー選択: `GET /system/menu/selectMenuTree/{menuId}`

## 入出力項目

### 入力項目

| 項目名 | 物理名 | 型 | 必須 | 最大長 | バリデーション | 説明 |
|--------|--------|-----|------|--------|----------------|------|
| メニューID | menuId | Long | - | - | hidden項目 | 編集対象メニューのID |
| 上級菜単ID | parentId | Long | - | - | hidden項目 | 親メニューのID |
| 菜単類型 | menuType | String | 必須 | 1 | M/C/F | 目録/菜単/按鈕 |
| 菜単名称 | menuName | String | 必須 | 50 | 重複チェック（同一親配下、自身除外） | メニューの表示名 |
| 請求地址 | url | String | - | 200 | - | アクセスURL |
| 打開方式 | target | String | - | - | menuItem/menuBlank | 頁簽/新窗口 |
| 権限標識 | perms | String | - | 100 | - | @RequiresPermissionsで使用 |
| 顕示順序 | orderNum | String | 必須 | - | 数字のみ | 表示順（小さいほど前） |
| 図標 | icon | String | - | - | - | Font Awesomeアイコンクラス |
| 菜単状態 | visible | String | - | 1 | 0:顕示、1:隠蔽 | 辞書から取得 |
| 是否刷新 | isRefresh | String | - | 1 | 0:刷新、1:不刷新 | ページタブ再読込設定 |

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

| 項目名 | 物理名 | 型 | 説明 |
|--------|--------|-----|------|
| メニュー情報 | menu | SysMenu | 編集対象メニューの全情報 |

## 表示項目

| 表示項目 | 説明 | 初期値/条件 |
|----------|------|-------------|
| 上級菜単選択欄 | テキスト表示+検索アイコン、クリックでツリー選択 | 親メニュー名（parentName） |
| 菜単類型ラジオ | 3択（目録/菜単/按鈕） | 既存の選択状態 |
| 菜単名称入力欄 | テキスト入力 | 既存の名称 |
| 請求地址入力欄 | テキスト入力、ヘルプテキスト付き | 既存のURL、菜単タイプのみ表示 |
| 打開方式セレクト | ドロップダウン（頁簽/新窗口） | 既存の設定、菜単タイプのみ表示 |
| 権限標識入力欄 | テキスト入力、ヘルプテキスト付き | 既存の権限標識、菜単/按鈕タイプで表示 |
| 顕示順序入力欄 | テキスト入力 | 既存の順序 |
| 図標入力欄 | テキスト入力、クリックでドロップダウン表示 | 既存のアイコン、目録/菜単タイプで表示 |
| 菜単状態ラジオ | 辞書からの選択肢 | 既存の状態 |
| 是否刷新ラジオ | はい/いいえ | 既存の設定、菜単タイプのみ表示 |

### 菜単類型による表示制御

| 項目 | M（目録） | C（菜単） | F（按鈕） |
|------|----------|----------|----------|
| 請求地址 | 非表示 | 表示 | 非表示 |
| 打開方式 | 非表示 | 表示 | 非表示 |
| 権限標識 | 非表示 | 表示 | 表示 |
| 図標 | 表示 | 表示 | 非表示 |
| 是否刷新 | 非表示 | 表示 | 非表示 |

## イベント仕様

### 1-画面表示

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

**処理フロー**：
1. 親画面から`$.operate.editTab(menuId)`で呼び出される
2. `SysMenuController.edit()`がmenuIdを受け取る
3. `menuService.selectMenuById()`でメニュー情報を取得
4. ModelMapにメニュー情報を設定
5. Thymeleafテンプレートを描画、各項目に既存値をバインド
6. JavaScript初期化処理でmenuTypeに応じた表示制御を実行

### 2-上級菜単選択

メニューツリー選択ダイアログを表示する。

**処理フロー**：
1. 上級菜単入力欄またはアイコンをクリック
2. `selectMenuTree()`関数が呼び出される
3. parentId > 0 の場合のみ選択可能（主菜単は変更不可）
4. `$.modal.openOptions()`でメニューツリーダイアログを表示
5. ダイアログで選択後、`doSubmit()`コールバックが呼び出される
6. 選択されたparentIdとmenuNameを親画面に反映

### 3-菜単類型変更

メニュー類型変更に応じて入力項目の表示/非表示を切り替える。

**処理フロー**：
1. 類型ラジオボタン変更で`ifChecked`イベントが発火
2. `menuVisible(menuType)`関数が呼び出される
3. 選択された類型（M/C/F）に応じて各項目の表示/非表示を制御
4. 目録（M）: url/perms/target/刷新を非表示、iconを表示
5. 菜単（C）: 全項目を表示
6. 按鈕（F）: url/icon/target/刷新を非表示、permsを表示

### 4-アイコン選択

アイコン選択ドロップダウンを表示する。

**処理フロー**：
1. 図標入力欄にフォーカスで`.icon-drop`を表示
2. アイコン一覧が表示される
3. アイコンクリックでクラス名を入力欄に設定
4. 入力欄外クリックでドロップダウンを非表示

### 5-メニュー名重複チェック（リアルタイム）

入力完了時にメニュー名の重複をチェックする。

**処理フロー**：
1. フォームバリデーションでremoteルールが発火
2. `POST /system/menu/checkMenuNameUnique`を呼び出し
3. menuId、parentId、menuNameをパラメータとして送信
4. 自身を除外した同一親配下で重複時はエラーメッセージ「菜单已经存在」を表示

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

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

**処理フロー**：
1. `submitHandler()`関数が呼び出される
2. `$.validate.form()`でクライアントバリデーション実行
3. バリデーション成功時、`$.operate.save()`でフォームをシリアライズして送信
4. サーバー側で重複チェック実行
5. `menuService.updateMenu()`でDB更新
6. 権限キャッシュをクリア
7. 成功時はモーダルを閉じて親画面を更新

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | sys_menu | UPDATE | メニューレコードを更新 |

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

#### sys_menu

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | parent_id | 入力値（parentId） | 親メニューID |
| UPDATE | menu_name | 入力値 | メニュー名称 |
| UPDATE | order_num | 入力値 | 表示順序 |
| UPDATE | url | 入力値 | リクエストURL |
| UPDATE | target | 入力値 | 打開方式 |
| UPDATE | menu_type | 入力値（M/C/F） | メニュー類型 |
| UPDATE | visible | 入力値（0/1） | 表示状態 |
| UPDATE | is_refresh | 入力値（0/1） | 刷新設定 |
| UPDATE | perms | 入力値 | 権限標識 |
| UPDATE | icon | 入力値 | アイコン |
| UPDATE | update_by | ログインユーザー名 | 更新者 |
| UPDATE | update_time | sysdate() | 更新日時 |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|----------|
| エラー | 菜单已经存在 | メニュー名が重複している場合 |
| エラー | 修改菜单'{menuName}'失败，菜单名称已存在 | 保存時にメニュー名重複 |
| エラー | 主菜单不能选择 | 主メニュー（parentId=0）で親選択を試みた場合 |
| 成功 | 操作成功 | 保存成功時 |

## 例外処理

| 例外状況 | 処理内容 |
|----------|----------|
| メニュー名重複 | エラーメッセージを表示して保存中断 |
| 主菜単の親変更試行 | 「主菜单不能选择」エラーを表示 |
| 通信エラー | エラーメッセージを表示 |
| セッションタイムアウト | ログイン画面へリダイレクト |
| バリデーションエラー | 該当項目にエラーメッセージを表示 |

## 備考

- 菜単状態の選択肢は辞書（sys_show_hide）から取得される
- 図標選択はFont Awesomeアイコンの一覧から選択
- 権限キャッシュは保存時にクリアされる
- 同一親配下でのメニュー名重複チェックでは、自身のmenuIdは除外される
- 主メニュー（parentId=0）の親は変更できない
- 打開方式でmenuBlankを選択すると新しいブラウザウィンドウで開く

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysMenu.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java` | メニューエンティティの構造、各フィールドのバリデーションを理解する |

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

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

**主要処理フロー**:
1. **121-127行目**: edit()メソッド - 画面表示処理、menuIdに基づくメニュー取得
2. **132-145行目**: editSave()メソッド - 保存処理、重複チェックと更新

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit.html | `ruoyi-admin/src/main/resources/templates/system/menu/edit.html` | 画面構造と動的表示制御を理解する |

**主要処理フロー**:
- **99-102行目**: 初期化時のmenuType取得と表示制御
- **104-138行目**: バリデーション設定（menuId含む重複チェック）
- **146-165行目**: アイコン選択とmenuType変更のイベントハンドラ
- **167-187行目**: menuVisible関数 - 類型に応じた表示制御
- **200-214行目**: selectMenuTree関数 - メニューツリー選択

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

```
[画面表示] edit.html
    │
    ├─ SysMenuController.edit()
    │      └─ menuService.selectMenuById()
    │
    ├─ [メニューツリー選択]
    │      └─ SysMenuController.selectMenuTree()
    │
    └─ [保存] submitHandler()
           └─ SysMenuController.editSave()
                  ├─ menuService.checkMenuNameUnique()
                  └─ menuService.updateMenu()
                         └─ SysMenuMapper.updateMenu()
```

### データフロー図

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

menuId(hidden) ─────────▶ menuService.selectMenuById() ───────▶ メニュー情報
                                                                 │
                                                                 ▼
                                                          [画面に表示]

menuId + フォーム入力 ──▶ menuService.updateMenu() ────────▶ sys_menu (UPDATE)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| edit.html | `ruoyi-admin/src/main/resources/templates/system/menu/edit.html` | テンプレート | メニュー編集画面のHTML/JavaScript |
| icon.html | `ruoyi-admin/src/main/resources/templates/system/menu/icon.html` | テンプレート | アイコン選択一覧（インクルード） |
| tree.html | `ruoyi-admin/src/main/resources/templates/system/menu/tree.html` | テンプレート | メニューツリー選択ダイアログ |
| SysMenuController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java` | コントローラー | HTTPリクエストの処理 |
| ISysMenuService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java` | インターフェース | メニューサービスの定義 |
| SysMenuServiceImpl.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java` | サービス実装 | メニューサービスの実装 |
| SysMenuMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml` | マッパー | メニューデータアクセスSQL |
| SysMenu.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java` | エンティティ | メニューデータモデル |
