# 機能設計書 60-投票作成・編集

## 概要

本ドキュメントは、QuickerSite CMSにおける投票作成・編集機能の設計を記載する。新規投票（アンケート）の作成および既存投票の編集・削除を行う機能である。

### 本機能の処理概要

投票作成・編集機能は、ウェブサイトに埋め込むアンケート・投票機能を設定するための管理画面である。投票質問、選択肢（最大12個）、表示オプション、投票期間などを設定できる。

**業務上の目的・背景**：ウェブサイト訪問者の意見収集や簡易アンケートの実施は、マーケティングやフィードバック収集において重要な機能である。本機能は、プログラミング知識がなくても管理者が容易に投票を設定・管理できるインターフェースを提供する。

**機能の利用シーン**：
- 新規投票を作成する場面
- 既存投票の質問や選択肢を編集する場面
- 投票のオンライン期間を設定する場面
- 投票結果をリセットする場面
- 不要な投票を削除する場面
- 投票結果の確認と分析を行う場面

**主要な処理内容**：
1. 投票基本情報の入力（質問文、埋め込みコード）
2. 選択肢の設定（最大12個、各選択肢に色指定可能）
3. 表示ラベルのカスタマイズ
4. オンライン期間・投票期限の設定
5. 投票結果の表示（棒グラフ形式）
6. 投票結果のリセット
7. 使用箇所検索（どのテンプレートで使用されているか）

**関連システム・外部連携**：特になし（内部処理のみ）

**権限による制御**：セカンドアドミンの投票権限（secondAdmin.bPoll）を持つユーザーのみがアクセス可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 64 | 投票編集 | 主画面 | 投票の作成・編集・削除 |
| 63 | 投票一覧 | 遷移先画面 | 保存・削除・リセット後のリダイレクト先 |

## 機能種別

データ登録（INSERT） / データ更新（UPDATE） / データ削除（DELETE）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| iPollID | String（暗号化） | No | 編集対象投票ID | 新規時は空 |
| sQuestion | String | Yes | 投票質問文 | 最大255文字 |
| sCode | String | Yes | 埋め込み用コード | 最大45文字 |
| bShowTitle | Boolean | No | 質問タイトル表示フラグ | true/false |
| dVoteFrom | Date | No | オンライン開始日 | 日付形式 |
| dVoteUntil | Date | No | オンライン終了日 | 日付形式 |
| dVoteDeadline | Date | No | 投票締切日 | 日付形式 |
| label_viewresults | String | Yes | 「結果を見る」ラベル | 最大255文字 |
| label_votenow | String | Yes | 「投票する」ラベル | 最大255文字 |
| label_numberofvotes | String | Yes | 「投票数」ラベル | [NMBR]を含む |
| sA1〜sA12 | String | No | 選択肢1〜12のテキスト | 各最大45文字 |
| sA1c〜sA12c | String | No | 選択肢1〜12の色 | 16進カラーコード |
| btnaction | String | - | ボタンアクション | save/delete/reset |
| QSSEC | String | 操作時 | CSRFトークン | 検証 |

### 入力データソース

- クエリパラメータ（iPollID）
- POSTフォームデータ（全入力項目）
- セッション（顧客ID: cId）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 投票フォーム | HTML | 入力フォーム全体 |
| 投票結果 | HTML | 棒グラフ形式の結果表示 |
| 使用箇所 | HTML | 投票コードの使用場所一覧 |

### 出力先

- 画面表示（HTML）
- リダイレクト（投票一覧へ）

## 処理フロー

### 処理シーケンス

```
1. セキュリティチェック
   └─ セカンドアドミンの投票権限を確認

2. 投票オブジェクト初期化
   └─ cls_pollインスタンス生成
   └─ iPollIDがあれば自動pick
   └─ bCanVote=false（管理画面では投票不可）

3. PostBackチェック
   └─ PostBack時はgetRequestValues()でフォーム値取得

4. ボタンアクション処理
   ├─ 保存ボタン（save）
   │   ├─ CSRF検証
   │   ├─ getRequestValues()
   │   ├─ poll.save()
   │   └─ 成功時は一覧へリダイレクト
   ├─ 削除ボタン（delete）
   │   ├─ CSRF検証
   │   ├─ poll.remove()
   │   └─ 一覧へリダイレクト
   └─ リセットボタン（reset）
       ├─ CSRF検証
       ├─ poll.reset()
       └─ 一覧へリダイレクト

5. 画面レンダリング
   └─ 入力フォーム表示
       ├─ 基本情報入力
       ├─ 選択肢入力（12個）+ カラーピッカー
       └─ 既存投票時のみ結果表示・リセットボタン

6. 使用箇所検索（既存投票時のみ）
   └─ cls_fullSearchで[QS_POLL:コード]を検索
   └─ 使用テンプレート一覧を表示
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[セキュリティチェック]
    B --> C[cls_poll生成]
    C --> D[bCanVote = false]
    D --> E{PostBack?}
    E -->|Yes| F[getRequestValues]
    E -->|No| G{ボタンアクション}
    F --> G
    G -->|save| H[CSRF検証]
    H --> I[getRequestValues]
    I --> J[poll.save]
    J --> K{保存成功?}
    K -->|Yes| L[一覧へリダイレクト]
    K -->|No| M[エラー表示]
    G -->|delete| N[CSRF検証]
    N --> O[poll.remove]
    O --> L
    G -->|reset| P[CSRF検証]
    P --> Q[poll.reset]
    Q --> L
    G -->|なし| R[フォーム表示]
    M --> R
    R --> S{既存投票?}
    S -->|Yes| T[結果表示]
    T --> U[使用箇所検索]
    S -->|No| V[終了]
    U --> V
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-60-001 | 必須項目 | sQuestion、sCodeは必須 | 保存時 |
| BR-60-002 | 選択肢上限 | 選択肢は最大12個まで | 全投票 |
| BR-60-003 | デフォルト色 | 各選択肢にデフォルト色が設定される | 新規作成時 |
| BR-60-004 | 投票数ラベル | [NMBR]を実際の投票数で置換 | 結果表示時 |
| BR-60-005 | リセット日時記録 | リセット時にdResetDateを記録 | リセット時 |
| BR-60-006 | オンライン判定 | dVoteFrom〜dVoteUntilの期間内のみ投票可能 | 投票時 |
| BR-60-007 | 投票締切判定 | dVoteDeadlineを過ぎると投票不可 | 投票時 |

### 計算ロジック

- 投票率（%）= (選択肢の投票数 / 総投票数) * 100
- 投票数ラベル置換: label_numberofvotesの`[NMBR]`を実際の総投票数で置換

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 新規作成 | tblPoll | INSERT | 投票レコードを新規作成 |
| 編集 | tblPoll | UPDATE | 投票レコードを更新 |
| 削除 | tblPoll | DELETE | 投票レコードを削除 |
| 削除 | tblPollVote | DELETE | 関連する投票結果を削除 |
| リセット | tblPollVote | DELETE | 投票結果のみ削除 |
| リセット | tblPoll | UPDATE | dResetDateを更新 |

### テーブル別操作詳細

#### tblPoll

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | sQuestion | フォーム入力値 | 投票質問文 |
| INSERT/UPDATE | sCode | フォーム入力値 | 埋め込みコード |
| INSERT/UPDATE | iCustomerID | cId | 顧客ID |
| INSERT/UPDATE | bShowTitle | フォーム入力値 | タイトル表示フラグ |
| INSERT/UPDATE | label_viewresults | フォーム入力値 | 結果表示ラベル |
| INSERT/UPDATE | label_votenow | フォーム入力値 | 投票ラベル |
| INSERT/UPDATE | label_numberofvotes | フォーム入力値 | 投票数ラベル |
| INSERT/UPDATE | dVoteFrom | フォーム入力値 | オンライン開始日 |
| INSERT/UPDATE | dVoteUntil | フォーム入力値 | オンライン終了日 |
| INSERT/UPDATE | dVoteDeadline | フォーム入力値 | 投票締切日 |
| INSERT/UPDATE | sA1〜sA15 | フォーム入力値 | 選択肢テキスト |
| INSERT/UPDATE | sA1c〜sA15c | フォーム入力値 | 選択肢色 |
| INSERT | dCreatedTS | now() | 作成日時 |
| UPDATE | dResetDate | now() | リセット時のみ |

#### tblPollVote

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | count(*) | WHERE iPollID = 指定ID AND iVote = 選択肢番号 | 集計用 |
| DELETE | - | WHERE iPollID = 指定ID | 削除・リセット時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | 投票権限がないユーザーがアクセス | ログイン画面へリダイレクト |
| err_mandatory | 入力エラー | sQuestion、sCodeが空 | エラーメッセージ表示 |

### リトライ仕様

- 特になし

## トランザクション仕様

- save処理はAddNew/Updateでの単一処理
- remove処理はtblPollVote削除 → tblPoll削除の順序
- reset処理はtblPollVote削除 → tblPoll更新の順序

## パフォーマンス要件

- 選択肢ごとにSELECT COUNT(*)クエリを実行（最大15回）
- 使用箇所検索は全テンプレートを対象とするため処理時間がかかる可能性あり

## セキュリティ考慮事項

- セカンドアドミンの投票権限チェック
- 全操作（保存・削除・リセット）でCSRFトークン検証
- 削除・リセット操作時はconfirmダイアログで誤操作防止
- quotRep関数によるXSS対策
- bCanVote=falseで管理画面からの投票を防止

## 備考

- 埋め込みコード形式：`[QS_POLL:コード]`
- 選択肢のデフォルト色は3系統（グレー、緑、青、ピンク）×3階調
- カラーピッカー（JQColorPicker）で各選択肢の色を視覚的に選択可能
- 投票結果は棒グラフ形式で表示（色付きdivで描画）
- 画面にはフォーム形式で最大12選択肢分の入力欄を表示（データベースは15選択肢分のカラムを保持）

---

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

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

### 推奨読解順序

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

投票のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | poll.asp | `asp/includes/poll.asp` | cls_pollクラスのプロパティ定義（2-17行目） |
| 1-2 | poll.asp | `asp/includes/poll.asp` | Questionsディクショナリの初期化（18-65行目） |

**読解のコツ**: Questionsはディクショナリで、キーが選択肢番号（1〜15）、値は配列(0:色, 1:テキスト)。Class_Initializeでデフォルト色が設定される。

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

編集画面の処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bs_pollEdit.asp | `asp/bs_pollEdit.asp` | 投票編集画面の全体フロー |

**主要処理フロー**:
1. **4行目**: セキュリティチェック（logon.hasaccess secondAdmin.bPoll）
2. **5-6行目**: cls_poll生成、bCanVote=false設定
3. **8-11行目**: PostBack判定とgetRequestValues
4. **12-26行目**: ボタンアクション処理（save/delete/reset）
5. **27行目**: フォーム表示（日付ピッカー、入力フィールド）
6. **28-29行目**: 選択肢入力（12個ループ）
7. **29-30行目**: カラーピッカー生成（12個ループ）
8. **32-42行目**: 使用箇所検索（cls_fullSearch）

#### Step 3: 投票クラスの詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | poll.asp | `asp/includes/poll.asp` | getRequestValues関数（66-83行目） |
| 3-2 | poll.asp | `asp/includes/poll.asp` | check関数（136-146行目）、save関数（147-186行目） |
| 3-3 | poll.asp | `asp/includes/poll.asp` | remove関数（187-195行目）、reset関数（196-204行目） |
| 3-4 | poll.asp | `asp/includes/poll.asp` | showresults関数（336-380行目） |

**主要処理フロー**:
- **66-83行目**: getRequestValuesでフォーム値をQuestionsディクショナリに格納
- **136-146行目**: check関数でsQuestion、sCodeの必須チェック
- **147-186行目**: save関数でtblPollにINSERT/UPDATE
- **187-195行目**: remove関数でtblPollVoteとtblPollを削除
- **196-204行目**: reset関数でtblPollVoteを削除し、dResetDateを更新
- **336-380行目**: showresults関数で投票結果を棒グラフ形式で生成

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

```
bs_pollEdit.asp
    |
    +-- begin.asp (include)
    |
    +-- bs_security.asp (include)
    |      +-- logon.hasaccess メソッド
    |
    +-- cls_poll クラス
    |      +-- Class_Initialize
    |      |      +-- pick() メソッド（自動呼び出し）
    |      |
    |      +-- getRequestValues() メソッド
    |      |
    |      +-- check() メソッド
    |      |      +-- message.AddError()
    |      |
    |      +-- save() メソッド
    |      |      +-- check() メソッド
    |      |      +-- db.GetDynamicRS
    |      |
    |      +-- remove() メソッド
    |      |      +-- tblPollVote DELETE
    |      |      +-- tblPoll DELETE
    |      |
    |      +-- reset() メソッド
    |      |      +-- tblPollVote DELETE
    |      |      +-- save() メソッド
    |      |
    |      +-- showresults() メソッド
    |             +-- SELECT COUNT(*) クエリ（15回）
    |
    +-- cls_fullSearch クラス
    |      +-- search() メソッド
    |
    +-- 各種ヘルパー関数
           +-- JQDatePicker() - 日付ピッカー
           +-- JQColorPicker() - カラーピッカー
           +-- encrypt() - ID暗号化
           +-- quotRep() - XSS対策
           +-- checkCSRF() - CSRF検証
```

### データフロー図

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

iPollID -------------------> cls_poll.pick() ------------> 投票データ取得
(暗号化パラメータ)           |
                            v
sQuestion -----------------> getRequestValues() ---------> Questions Dict
sCode                       |                              (選択肢配列)
sA1〜sA12                   |
sA1c〜sA12c                 |
                            v
btnaction=save -----------> check() --------------------> バリデーション
                            |
                            v
                      +-----+-----+
                      |     |     |
                   成功    失敗
                      |     |
                      v     v
              tblPoll   エラー表示
              INSERT/   (フォーム
              UPDATE    再表示)
                      |
                      v
              一覧へリダイレクト

btnaction=delete --------> remove() --------------------> tblPollVote DELETE
                            |                             tblPoll DELETE
                            v
                      一覧へリダイレクト

btnaction=reset ---------> reset() ---------------------> tblPollVote DELETE
                            |                             dResetDate更新
                            v
                      一覧へリダイレクト

既存投票 ----------------> showresults() ---------------> 棒グラフHTML
                            |
                            v
                      cls_fullSearch.search() ----------> 使用箇所一覧
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bs_pollEdit.asp | `asp/bs_pollEdit.asp` | ソース | 投票編集画面のメインファイル |
| bs_pollList.asp | `asp/bs_pollList.asp` | ソース | 投票一覧画面（リダイレクト先） |
| poll.asp | `asp/includes/poll.asp` | ソース | 投票クラス定義（cls_poll） |
| bs_pollBack.asp | `asp/bs_pollBack.asp` | ソース | 投票バック画面（テンプレート） |
| begin.asp | `asp/begin.asp` | ソース | 共通インクルード・初期化処理 |
| bs_security.asp | `asp/bs_security.asp` | ソース | セキュリティチェック処理 |
| fullSearch.asp | `asp/includes/fullSearch.asp` | ソース | 使用箇所検索クラス（cls_fullSearch） |
