# 画面設計書 17-アバター変更

## 概要

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

### 本画面の処理概要

アバター変更画面は、ログインユーザーが自身のプロフィール画像（アバター）を変更するための画面である。Cropper.jsライブラリを使用して、アップロードした画像をトリミング・加工してからサーバーに保存する機能を提供する。

**業務上の目的・背景**：ビジネスシステムにおいてもユーザーの識別やコミュニケーションの円滑化のためにプロフィール画像は重要である。本画面は、ユーザーが任意の画像をアップロードし、適切なサイズ・形状にトリミングした上でアバターとして設定できる機能を提供する。円形トリミングとプレビュー機能により、設定前に仕上がりを確認できる。

**画面へのアクセス方法**：プロフィール画面（No.16）からアバター画像または「修改头像」リンクをクリックすると、モーダルダイアログ形式でこの画面が表示される。URLパターンは `/system/user/profile/avatar` である。

**主要な操作・処理内容**：
1. 現在のアバター画像を表示し、Cropperで編集可能に
2. 「上传图像」ボタンで新しい画像をローカルから選択
3. Cropperの各種操作（拡大/縮小/回転/反転/リセット）
4. 3サイズ（小/中/大）のリアルタイムプレビュー表示
5. 「確定」ボタンでトリミング結果をサーバーに送信
6. 古いアバターファイルを削除し、新しいアバターを保存

**画面遷移**：
- 遷移元：プロフィール画面（No.16）
- 遷移先：なし（保存後はモーダルを閉じてプロフィール画面をリロード）

**権限による表示制御**：ログインユーザー自身のアバターのみ変更可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | プロファイル管理 | 主機能 | アバター画像のアップロード・変更処理 |
| 23 | ファイルアップロード | 補助機能 | 画像ファイルのアップロード処理 |

## 画面種別

編集（モーダルダイアログ形式・画像編集UI）

## URL/ルーティング

| メソッド | URL | 説明 |
|---------|-----|------|
| GET | /system/user/profile/avatar | アバター変更画面表示 |
| POST | /system/user/profile/updateAvatar | アバター画像保存 |

## 入出力項目

### 入力項目

| No | 項目名 | 物理名 | 型 | 桁数 | 必須 | 初期値 | バリデーション |
|----|--------|--------|----|----|------|--------|--------------|
| 1 | 画像ファイル | avatarfile | file | - | ○ | - | 画像ファイル形式（image/*） |

## 表示項目

| No | 項目名 | 説明 |
|----|--------|------|
| 1 | 画像編集エリア | Cropperで加工中の画像表示エリア |
| 2 | プレビュー（小） | 64x64pxの円形プレビュー |
| 3 | プレビュー（中） | 96x96pxの円形プレビュー |
| 4 | プレビュー（大） | 128x128pxの円形プレビュー |
| 5 | 操作ボタン群 | 拡大/縮小/左回転/右回転/水平反転/垂直反転/リセット |

## イベント仕様

### 1-画面初期表示

| 項目 | 内容 |
|------|------|
| トリガー | プロフィール画面からアバタークリック時 |
| 処理内容 | 1. ログインユーザーの現在のアバター画像URLを取得<br>2. Cropper.jsを初期化（aspectRatio: 1, viewMode: 1）<br>3. プレビューエリアにリアルタイム反映設定 |
| 呼び出しAPI | GET /system/user/profile/avatar |
| 遷移先 | - |

### 2-画像選択（上传图像）

| 項目 | 内容 |
|------|------|
| トリガー | 「上传图像」ボタン押下でファイル選択後 |
| 処理内容 | 1. FileReaderで選択された画像を読み込み<br>2. 画像形式チェック（/^image\/\w+$/）<br>3. Cropperの画像を差し替え（cropper.replace） |
| 呼び出しAPI | - |
| 遷移先 | - |

### 3-ズーム操作（拡大/縮小）

| 項目 | 内容 |
|------|------|
| トリガー | 拡大/縮小ボタン押下時 |
| 処理内容 | cropper.zoom(0.1) または cropper.zoom(-0.1) を実行 |
| 呼び出しAPI | - |
| 遷移先 | - |

### 4-回転操作（左回転/右回転）

| 項目 | 内容 |
|------|------|
| トリガー | 回転ボタン押下時 |
| 処理内容 | cropper.rotate(-45) または cropper.rotate(45) を実行 |
| 呼び出しAPI | - |
| 遷移先 | - |

### 5-反転操作（水平/垂直）

| 項目 | 内容 |
|------|------|
| トリガー | 反転ボタン押下時 |
| 処理内容 | cropper.scaleX(-1) または cropper.scaleY(-1) を実行（トグル動作） |
| 呼び出しAPI | - |
| 遷移先 | - |

### 6-リセット操作

| 項目 | 内容 |
|------|------|
| トリガー | リセットボタン押下時 |
| 処理内容 | cropper.reset() で初期状態に戻す |
| 呼び出しAPI | - |
| 遷移先 | - |

### 7-確定ボタン押下（submitHandler）

| 項目 | 内容 |
|------|------|
| トリガー | ダイアログの「確定」ボタン押下時 |
| 処理内容 | 1. Cropperからトリミング済み画像をBlob取得（getCroppedCanvas().toBlob）<br>2. FormDataにavatarfileとしてBlob追加<br>3. Ajax POSTでサーバーに送信<br>4. 成功時、古いアバターを削除して新アバターを保存<br>5. セッションのアバター情報を更新<br>6. ダイアログを閉じてプロフィール画面をリロード |
| 呼び出しAPI | POST /system/user/profile/updateAvatar |
| 遷移先 | プロフィール画面（リロード） |

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 確定ボタン押下 | sys_user | UPDATE | アバターパスの更新 |

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

#### sys_user

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | avatar | 新しいアバター画像のパス | /profile/avatar/yyyy/MM/dd/xxx.png形式 |

## メッセージ仕様

| No | 種別 | メッセージ | 表示条件 |
|----|------|----------|----------|
| 1 | 成功 | 操作成功 | アバター更新成功時 |
| 2 | 警告 | 裁剪框加载中,请稍候... | Cropper未準備完了時に操作した場合 |
| 3 | 警告 | 请选择一个图片文件。 | 画像以外のファイルを選択した場合 |
| 4 | エラー | (エラーメッセージ) | ファイルアップロード失敗時 |

## 例外処理

| 例外パターン | 対応処理 |
|------------|---------|
| 画像形式エラー | 画像ファイル以外が選択された場合、警告メッセージを表示 |
| Cropper未準備 | Cropper読み込み完了前に操作した場合、警告メッセージを表示 |
| アップロードエラー | サーバーエラー時、エラーメッセージを表示 |

## 備考

- Cropper.js v1.xを使用
- aspectRatio: 1で正方形トリミングを強制
- viewMode: 1でキャンバス領域内に画像を制限
- autoCropArea: 0.9で初期トリミング領域を90%に設定
- HTMLCanvasElement.prototype.toBlobのポリフィルを含む（IE対応）
- 古いアバターファイルはファイルシステムから物理削除

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysProfileController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java` | avatar()とupdateAvatar()メソッド |

**主要処理フロー**:
1. **113-120行目**: `avatar()` メソッド - 画面表示、現在のアバター情報取得
2. **151-184行目**: `updateAvatar()` メソッド - アバター保存処理、古いファイル削除

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | avatar.html | `ruoyi-admin/src/main/resources/templates/system/user/profile/avatar.html` | Cropper初期化、各種操作ボタン |

**主要処理フロー**:
- **134-167行目**: 画像編集エリアとプレビュー領域
- **172-182行目**: Cropper初期化（aspectRatio, viewMode, autoCropArea, preview）
- **184-197行目**: ファイル選択時の画像差し替え処理
- **199-212行目**: 操作ボタンのイベントハンドラ
- **215-234行目**: submitHandler()関数（Blob取得とAjax送信）

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

```
プロフィール画面 [アバター]クリック
    │
    ├─ layer.open() → モーダルダイアログ表示
    │      │
    │      └─ SysProfileController.avatar()       ← GET /profile/avatar
    │             └─ userService.selectUserById()  ← ユーザー情報取得
    │
    └─ avatar.html 表示
           │
           ├─ Cropper.js 初期化
           │
           ├─ [上传图像] → ファイル選択 → cropper.replace()
           │
           ├─ [操作ボタン] → zoom/rotate/scale/reset
           │
           └─ [確定]ボタン
                  │
                  ├─ getCroppedCanvas().toBlob()
                  │
                  └─ Ajax POST → SysProfileController.updateAvatar()
                         ├─ FileUploadUtils.upload()  ← ファイル保存
                         ├─ userService.updateUserAvatar()  ← DB更新
                         └─ FileUtils.deleteFile()  ← 古いファイル削除
```

### データフロー図

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

画像ファイル
(inputImage)         ブラウザ側                           プレビュー表示
     │               ├─ FileReader                        │
     │               └─ Cropper編集                   ───▶ .img-preview
     │
     ▼
getCroppedCanvas()
     │
     ▼               SysProfileController.updateAvatar()
Blob (avatarfile) ───▶  │
                        ├─ FileUploadUtils.upload()  ───▶ ファイル保存
                        ├─ updateUserAvatar()        ───▶ sys_user.avatar更新
                        └─ deleteFile()             ───▶ 古いファイル削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SysProfileController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java` | コントローラー | avatar(), updateAvatar()メソッド |
| avatar.html | `ruoyi-admin/src/main/resources/templates/system/user/profile/avatar.html` | テンプレート | アバター変更画面UI（Cropper.js） |
| FileUploadUtils.java | `ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java` | ユーティリティ | ファイルアップロード処理 |
| FileUtils.java | `ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java` | ユーティリティ | ファイル削除処理 |
| SysUserMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml` | Mapper | updateUserAvatar SQL（169-171行目） |
| cropper.min.js | `ruoyi-admin/src/main/resources/static/ajax/libs/cropper/cropper.min.js` | JavaScript | Cropper.jsライブラリ |
