# 画面設計書 11-ユーザー編集

## 概要

本ドキュメントは、RuoYi後台管理システムにおけるユーザー編集画面の設計仕様を定義するものである。

### 本画面の処理概要

ユーザー編集画面は、システムに登録済みの既存ユーザー情報を修正・更新するための画面である。管理者がユーザー管理一覧画面から特定のユーザーを選択して編集操作を行う際に利用される。

**業務上の目的・背景**：組織変更によるユーザーの所属部門変更、連絡先情報の更新、ロール権限の見直しなど、ユーザー情報は継続的に変更される必要がある。本画面は、システム管理者がユーザーのライフサイクルに応じて適切に情報を更新できる機能を提供し、セキュリティとアクセス制御を維持するための重要な役割を担う。

**画面へのアクセス方法**：ユーザー管理一覧画面から対象ユーザーの「編集」ボタンをクリックすると、モーダルウィンドウ形式でこの画面が表示される。URLパターンは `/system/user/edit/{userId}` で、userIdパスパラメータで編集対象のユーザーを特定する。

**主要な操作・処理内容**：
1. 画面表示時に対象ユーザーの現在情報（ユーザー名、部門、電話番号、メール、岗位、性別、ロール、備考）をフォームに反映
2. 部門選択ボタンから部門ツリー選択ダイアログを起動し、所属部門を変更
3. フォーム入力値のバリデーション（メール形式チェック、電話番号重複チェック）
4. 「保存」ボタンでユーザー情報を更新し、一覧画面を更新
5. 「閉じる」ボタンで変更を保存せずにダイアログを閉じる

**画面遷移**：
- 遷移元：ユーザー管理一覧画面（No.9）
- 遷移先：部門ツリー選択画面（No.15）（モーダル内遷移）
- 戻り先：ユーザー管理一覧画面（保存後または閉じる操作時）

**権限による表示制御**：本画面へのアクセスには `system:user:edit` 権限が必要。ログイン名は編集不可（読み取り専用）として表示される。管理者ユーザー（admin）自身を編集する場合、一部機能が制限される。停用状態のロールや岗位は選択不可状態で表示される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ユーザー管理 | 主機能 | ユーザー情報の更新保存処理 |
| 2 | ロール管理 | 補助機能 | ロール選択リストの取得処理 |
| 5 | 役職管理 | 補助機能 | 役職選択リストの取得処理 |
| 4 | 部門管理 | 補助機能 | 部門ツリー選択処理 |

## 画面種別

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

## URL/ルーティング

| メソッド | URL | 説明 |
|---------|-----|------|
| GET | /system/user/edit/{userId} | 編集画面表示 |
| POST | /system/user/edit | ユーザー情報更新 |
| POST | /system/user/checkEmailUnique | メール重複チェック |
| POST | /system/user/checkPhoneUnique | 電話番号重複チェック |

## 入出力項目

### 入力項目

| No | 項目名 | 物理名 | 型 | 桁数 | 必須 | 初期値 | バリデーション |
|----|--------|--------|----|----|------|--------|--------------|
| 1 | ユーザーID | userId | hidden | - | ○ | 対象ユーザーID | - |
| 2 | 部門ID | deptId | hidden | - | - | 対象ユーザーの部門ID | - |
| 3 | ユーザー名称 | userName | text | 30 | ○ | 対象ユーザー名 | 30文字以内 |
| 4 | 部門名称 | deptName | text(読取専用) | - | - | 対象部門名 | クリックで部門選択ダイアログ起動 |
| 5 | 手機号碼 | phonenumber | text | 11 | - | 対象ユーザーの電話番号 | 11桁以内、電話番号形式、重複不可 |
| 6 | 邮箱 | email | text | 50 | - | 対象ユーザーのメール | 50文字以内、メール形式、重複不可 |
| 7 | 登録帳號 | loginName | text(読取専用) | - | - | 対象ユーザーのログイン名 | 変更不可 |
| 8 | 用戸状態 | status | checkbox | - | - | 対象ユーザーの状態 | true:正常(0), false:停用(1) |
| 9 | 岗位 | postIds | select(multiple) | - | - | 対象ユーザーの岗位 | 複数選択可 |
| 10 | 用戸性別 | sex | select | - | - | 対象ユーザーの性別 | 0:男, 1:女, 2:未知 |
| 11 | 角色 | roleIds | checkbox(multiple) | - | - | 対象ユーザーのロール | 複数選択可 |
| 12 | 備考 | remark | textarea | 500 | - | 対象ユーザーの備考 | 500文字以内 |

## 表示項目

| No | 項目名 | 説明 |
|----|--------|------|
| 1 | 基本信息セクション | ユーザーの基本情報入力フォーム |
| 2 | 其他信息セクション | 備考入力フォーム |
| 3 | 岗位リスト | システムに登録されている岗位の選択リスト（停用の岗位は選択不可） |
| 4 | ロールリスト | システムに登録されているロールのチェックボックスリスト（停用のロールは選択不可） |

## イベント仕様

### 1-画面初期表示

| 項目 | 内容 |
|------|------|
| トリガー | ユーザー管理一覧画面から「編集」ボタン押下時 |
| 処理内容 | 1. コントローラーがuserIdパラメータを受け取り、該当ユーザー情報を取得<br>2. ユーザーに紐づくロール一覧を取得<br>3. ユーザーに紐づく岗位一覧を取得<br>4. モーダルウィンドウを表示し、フォームに値をバインド |
| 呼び出しAPI | GET /system/user/edit/{userId} |
| 遷移先 | - |

### 2-部門選択ボタン押下

| 項目 | 内容 |
|------|------|
| トリガー | 部門名フィールドクリック時 |
| 処理内容 | 1. 部門ツリー選択ダイアログを開く<br>2. ユーザーが部門を選択後、deptIdとdeptNameを更新 |
| 呼び出しAPI | GET /system/user/selectDeptTree/{deptId} |
| 遷移先 | 部門ツリー選択画面（モーダル内） |

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

| 項目 | 内容 |
|------|------|
| トリガー | 「保存」ボタン押下時 |
| 処理内容 | 1. フォームバリデーション実行<br>2. バリデーションエラーがあれば処理中断<br>3. statusチェックボックスの値を0/1に変換<br>4. 選択されたroleIds、postIdsを取得<br>5. フォームデータをシリアライズしてPOST送信<br>6. 成功時はモーダルを閉じて一覧を更新 |
| 呼び出しAPI | POST /system/user/edit |
| 遷移先 | ユーザー管理一覧画面（更新後） |

### 4-閉じるボタン押下

| 項目 | 内容 |
|------|------|
| トリガー | 「閉じる」ボタン押下時 |
| 処理内容 | モーダルウィンドウを閉じる |
| 呼び出しAPI | - |
| 遷移先 | ユーザー管理一覧画面 |

### 5-メール入力時リモートバリデーション

| 項目 | 内容 |
|------|------|
| トリガー | メールフィールドからフォーカスが外れた時 |
| 処理内容 | 1. 入力されたメールが既存ユーザーと重複していないか非同期確認<br>2. 重複時はエラーメッセージ「Email已经存在」を表示 |
| 呼び出しAPI | POST /system/user/checkEmailUnique |
| 遷移先 | - |

### 6-電話番号入力時リモートバリデーション

| 項目 | 内容 |
|------|------|
| トリガー | 電話番号フィールドからフォーカスが外れた時 |
| 処理内容 | 1. 入力された電話番号が既存ユーザーと重複していないか非同期確認<br>2. 重複時はエラーメッセージ「手机号码已经存在」を表示 |
| 呼び出しAPI | POST /system/user/checkPhoneUnique |
| 遷移先 | - |

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | sys_user | UPDATE | ユーザー基本情報の更新 |
| 保存ボタン押下 | sys_user_role | DELETE | 既存のユーザーロール関連を削除 |
| 保存ボタン押下 | sys_user_role | INSERT | 新しいユーザーロール関連を登録 |
| 保存ボタン押下 | sys_user_post | DELETE | 既存のユーザー岗位関連を削除 |
| 保存ボタン押下 | sys_user_post | INSERT | 新しいユーザー岗位関連を登録 |

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

#### sys_user

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | dept_id | 選択した部門ID | 部門変更時 |
| UPDATE | user_name | 入力されたユーザー名称 | - |
| UPDATE | email | 入力されたメールアドレス | - |
| UPDATE | phonenumber | 入力された電話番号 | - |
| UPDATE | sex | 選択された性別コード | 0:男, 1:女, 2:未知 |
| UPDATE | status | ステータス状態 | 0:正常, 1:停用 |
| UPDATE | remark | 入力された備考 | - |
| UPDATE | update_by | ログインユーザーのログイン名 | 更新者 |
| UPDATE | update_time | sysdate() | 更新日時 |

#### sys_user_role

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | user_id = #{userId} | 既存関連の削除 |
| INSERT | user_id | 対象ユーザーID | - |
| INSERT | role_id | 選択されたロールID | 選択数分繰り返し |

#### sys_user_post

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | user_id = #{userId} | 既存関連の削除 |
| INSERT | user_id | 対象ユーザーID | - |
| INSERT | post_id | 選択された岗位ID | 選択数分繰り返し |

## メッセージ仕様

| No | 種別 | メッセージ | 表示条件 |
|----|------|----------|----------|
| 1 | エラー | Email已经存在 | メール重複チェックで既存メールが見つかった場合 |
| 2 | エラー | 手机号码已经存在 | 電話番号重複チェックで既存番号が見つかった場合 |
| 3 | エラー | 修改用户'xxx'失败，登录账号已存在 | ログイン名重複時（通常発生しない） |
| 4 | エラー | 修改用户'xxx'失败，手机号码已存在 | サーバー側電話番号重複検証失敗時 |
| 5 | エラー | 修改用户'xxx'失败，邮箱账号已存在 | サーバー側メール重複検証失敗時 |
| 6 | 成功 | 操作成功 | ユーザー情報更新成功時 |

## 例外処理

| 例外パターン | 対応処理 |
|------------|---------|
| データ権限不足 | 編集対象ユーザーへのデータ権限がない場合、アクセス拒否エラー |
| 管理者編集制限 | admin（userId=1）の削除操作など特定操作は禁止 |
| 対象ユーザー不存在 | 編集対象のユーザーIDが存在しない場合、エラー画面表示 |
| 通信エラー | Ajax通信失敗時、システムエラーメッセージを表示 |

## 備考

- Select2プラグインを使用して岗位選択リストを実装
- jQueryValidateを使用したフォームバリデーション
- ログイン名（loginName）は編集画面で変更不可（readonly属性）
- 管理者ロール（roleId=1）は非管理者ユーザーには表示されない

---

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

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

### 推奨読解順序

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

まず、ユーザー情報を表すドメインオブジェクトの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysUser.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java` | ユーザーエンティティの構造、roleIds/postIdsフィールドがロール・岗位関連を保持 |
| 1-2 | SysRole.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java` | ロールエンティティ、flagフィールドでユーザーとの関連を示す |
| 1-3 | SysPost.java | `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java` | 岗位エンティティの構造 |

**読解のコツ**: SysUserはSysDeptおよびList<SysRole>を内包する複合構造。roleIds/postIdsはLong[]型で画面からの入力を受け取る。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SysUserController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java` | 編集画面表示・保存処理のエントリーポイント |

**主要処理フロー**:
1. **159-168行目**: `edit()` メソッド - 編集画面表示、ユーザー/ロール/岗位情報をモデルに設定
2. **187-212行目**: `editSave()` メソッド - ユーザー情報更新処理、各種チェックと更新実行

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

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

**主要処理フロー**:
- `updateUser()`: トランザクション内でユーザー情報更新、ロール関連削除・挿入、岗位関連削除・挿入を実行

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SysUserMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml` | updateUser SQLの確認（185-206行目） |
| 4-2 | SysUserRoleMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml` | ユーザーロール関連の削除・挿入SQL |
| 4-3 | SysUserPostMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml` | ユーザー岗位関連の削除・挿入SQL |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | edit.html | `ruoyi-admin/src/main/resources/templates/system/user/edit.html` | Thymeleafテンプレート、フォーム構造、JavaScript処理 |

**主要処理フロー**:
- **9-123行目**: フォーム構造とデータバインディング
- **137-182行目**: jQueryValidateによるバリデーション設定
- **184-195行目**: `submitHandler()` 関数による保存処理
- **197-222行目**: `selectDeptTree()` 関数による部門選択ダイアログ制御

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

```
ユーザー管理一覧画面 [編集]ボタン押下
    │
    ├─ SysUserController.edit()                 ← GET /system/user/edit/{userId}
    │      ├─ userService.checkUserDataScope()     ← 権限チェック
    │      ├─ roleService.selectRolesByUserId()    ← ロール一覧取得
    │      ├─ userService.selectUserById()         ← ユーザー情報取得
    │      └─ postService.selectPostsByUserId()    ← 岗位一覧取得
    │
    └─ edit.html 表示
           │
           ├─ [部門選択]クリック
           │      └─ selectDeptTree() → deptTree.html表示
           │
           └─ [保存]ボタン押下
                  │
                  ├─ submitHandler() → $.operate.saveTab()
                  │
                  └─ SysUserController.editSave()       ← POST /system/user/edit
                         ├─ userService.checkUserAllowed()
                         ├─ userService.checkUserDataScope()
                         ├─ deptService.checkDeptDataScope()
                         ├─ roleService.checkRoleDataScope()
                         ├─ userService.checkLoginNameUnique()
                         ├─ userService.checkPhoneUnique()
                         ├─ userService.checkEmailUnique()
                         │
                         └─ userService.updateUser()
                                ├─ userMapper.updateUser()
                                ├─ userRoleMapper.deleteUserRoleByUserId()
                                ├─ userRoleMapper.batchUserRole()
                                ├─ userPostMapper.deleteUserPostByUserId()
                                └─ userPostMapper.batchUserPost()
```

### データフロー図

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

フォーム入力値           SysUserController               sys_user更新
(userName,email等)  ───▶    ├─ バリデーション           ├─ user_name
                           ├─ 権限チェック             ├─ email
roleIdsチェック     ───▶    └─ SysUserService          ├─ phonenumber
postIds選択         ───▶        └─ updateUser()        └─ 他フィールド

                                    ↓
                                                         sys_user_role
                           ユーザーロール関連更新  ───▶  DELETE/INSERT
                                    ↓
                           ユーザー岗位関連更新   ───▶  sys_user_post
                                                         DELETE/INSERT
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SysUserController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java` | コントローラー | リクエスト処理 |
| edit.html | `ruoyi-admin/src/main/resources/templates/system/user/edit.html` | テンプレート | 画面UI定義 |
| SysUser.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java` | エンティティ | ユーザードメイン |
| ISysUserService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java` | インターフェース | サービス定義 |
| SysUserServiceImpl.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java` | サービス実装 | ビジネスロジック |
| SysUserMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml` | Mapper | ユーザーSQL定義 |
| SysUserRoleMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml` | Mapper | ユーザーロール関連SQL |
| SysUserPostMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml` | Mapper | ユーザー岗位関連SQL |
| deptTree.html | `ruoyi-admin/src/main/resources/templates/system/user/deptTree.html` | テンプレート | 部門選択ダイアログ |
