diff --git a/app/Plugins/User/Forms/FormsPlugin.php b/app/Plugins/User/Forms/FormsPlugin.php
index 430a4aa5b..c59dfd9af 100644
--- a/app/Plugins/User/Forms/FormsPlugin.php
+++ b/app/Plugins/User/Forms/FormsPlugin.php
@@ -107,6 +107,7 @@ public function getPublicFunctions()
'editInput',
'thanks',
'editSpamFilter',
+ 'indexCount',
];
$functions['post'] = [
'index',
@@ -127,6 +128,7 @@ public function getPublicFunctions()
'addSpamList',
'deleteSpamList',
'addToSpamListFromInput',
+ 'indexCount',
];
return $functions;
}
@@ -3020,12 +3022,16 @@ public function listInputs($request, $page_id, $frame_id, $forms_id = null)
// カラムの取得
$columns = FormsColumns::where('forms_id', $form->id)->orderBy('display_sequence', 'asc')->get();
+ $search_condition = $this->getListInputsSearchCondition($request);
+
$inputs_query = FormsInputs::where('forms_id', $form->id);
+ $this->appendListInputsSearchWhere($inputs_query, $search_condition);
// $inputs_query->orderBy('forms_inputs.id', 'asc');
$inputs_query->orderBy('forms_inputs.created_at', 'desc');
// データ取得
- $get_count = 10;
+ $get_count = session("view_count_spectator_{$frame_id}", $this->getListInputsDefaultPerPage());
+ $get_count = $this->normalizeListInputsPerPage($get_count);
$inputs = $inputs_query->paginate($get_count, ["*"], "frame_{$frame_id}_page");
// 登録データ詳細の取得
@@ -3060,9 +3066,170 @@ public function listInputs($request, $page_id, $frame_id, $forms_id = null)
'inputs' => $inputs,
'input_cols' => $input_cols,
'has_email_map' => $has_email_map,
+ 'search_condition' => $search_condition,
+ 'per_page_options' => $this->getListInputsPerPageOptions(),
+ 'view_count' => $get_count,
]);
}
+ /**
+ * 登録一覧の件数指定
+ */
+ public function indexCount($request, $page_id, $frame_id)
+ {
+ session(["view_count_spectator_{$frame_id}" => $this->normalizeListInputsPerPage($request->input("view_count_spectator"))]);
+
+ // リダイレクト先を指定しないため、画面から渡されたredirect_pathに飛ぶ
+ }
+
+ /**
+ * 登録一覧の検索条件を画面入力から取得する。
+ */
+ private function getListInputsSearchCondition($request): array
+ {
+ return [
+ 'keyword' => trim((string)$request->input('keyword', '')),
+ 'status' => $this->normalizeListInputsStatus($request->input('status')),
+ 'created_from' => $this->normalizeListInputsDate($request->input('created_from')),
+ 'created_to' => $this->normalizeListInputsDate($request->input('created_to')),
+ ];
+ }
+
+ /**
+ * 登録一覧の検索条件をクエリに反映する。
+ */
+ private function appendListInputsSearchWhere($inputs_query, array $search_condition): void
+ {
+ if ($search_condition['keyword'] !== '') {
+ $keyword = $this->escapeLikeValue($search_condition['keyword']);
+ $like_keyword = '%' . $keyword . '%';
+
+ $inputs_query->where(function ($query) use ($like_keyword) {
+ $query->where('forms_inputs.number_with_prefix', 'like', $like_keyword)
+ ->orWhere('forms_inputs.created_name', 'like', $like_keyword)
+ ->orWhere('forms_inputs.ip_address', 'like', $like_keyword)
+ ->orWhereExists(function ($sub_query) use ($like_keyword) {
+ $sub_query->select(DB::raw(1))
+ ->from('forms_input_cols')
+ ->join('forms_columns', 'forms_columns.id', '=', 'forms_input_cols.forms_columns_id')
+ ->whereColumn('forms_input_cols.forms_inputs_id', 'forms_inputs.id')
+ ->where('forms_columns.column_type', '<>', FormColumnType::file)
+ ->where('forms_input_cols.value', 'like', $like_keyword);
+ })
+ ->orWhereExists(function ($sub_query) use ($like_keyword) {
+ $sub_query->select(DB::raw(1))
+ ->from('forms_input_cols')
+ ->join('forms_columns', 'forms_columns.id', '=', 'forms_input_cols.forms_columns_id')
+ ->join('uploads', 'uploads.id', '=', 'forms_input_cols.value')
+ ->whereColumn('forms_input_cols.forms_inputs_id', 'forms_inputs.id')
+ ->where('forms_columns.column_type', FormColumnType::file)
+ ->where('uploads.client_original_name', 'like', $like_keyword);
+ });
+ });
+ }
+
+ if ($search_condition['status'] !== '') {
+ $inputs_query->where('forms_inputs.status', (int)$search_condition['status']);
+ }
+
+ if ($search_condition['created_from'] !== '') {
+ $inputs_query->whereDate('forms_inputs.created_at', '>=', $search_condition['created_from']);
+ }
+
+ if ($search_condition['created_to'] !== '') {
+ $inputs_query->whereDate('forms_inputs.created_at', '<=', $search_condition['created_to']);
+ }
+ }
+
+ /**
+ * 登録一覧の状態検索条件を有効な値に丸める。
+ */
+ private function normalizeListInputsStatus($status): string
+ {
+ if (is_null($status) || $status === '') {
+ return '';
+ }
+
+ $allowed_statuses = array_map('strval', array_keys(FormStatusType::enum));
+ $status = (string)$status;
+
+ return in_array($status, $allowed_statuses, true) ? $status : '';
+ }
+
+ /**
+ * 登録一覧の日付検索条件を有効な年月日に丸める。
+ */
+ private function normalizeListInputsDate($date): string
+ {
+ if (!is_string($date) || $date === '') {
+ return '';
+ }
+
+ $date = trim($date);
+ if (!preg_match('/\A[0-9]{4}-[0-9]{2}-[0-9]{2}\z/', $date)) {
+ return '';
+ }
+
+ [$year, $month, $day] = array_map('intval', explode('-', $date));
+
+ return checkdate($month, $day, $year) ? $date : '';
+ }
+
+ /**
+ * 登録一覧の表示件数を許可された値に丸める。
+ */
+ private function normalizeListInputsPerPage($per_page): int
+ {
+ $per_page = (int)$per_page;
+ $per_page_options = $this->getListInputsPerPageOptions();
+
+ return in_array($per_page, $per_page_options, true) ? $per_page : $this->getListInputsDefaultPerPage();
+ }
+
+ /**
+ * 登録一覧の表示件数候補を設定から取得する。
+ */
+ private function getListInputsPerPageOptions(): array
+ {
+ $per_page_options = config('forms.list_inputs.per_page_options', []);
+ if (!is_array($per_page_options)) {
+ return [10];
+ }
+
+ $per_page_options = collect($per_page_options)
+ ->map(function ($per_page) {
+ return (int)$per_page;
+ })
+ ->filter(function ($per_page) {
+ return $per_page > 0;
+ })
+ ->unique()
+ ->sort()
+ ->values()
+ ->all();
+
+ return $per_page_options ?: [10];
+ }
+
+ /**
+ * 登録一覧の初期表示件数を設定から取得する。
+ */
+ private function getListInputsDefaultPerPage(): int
+ {
+ $default_per_page = (int)config('forms.list_inputs.default_per_page');
+ $per_page_options = $this->getListInputsPerPageOptions();
+
+ return in_array($default_per_page, $per_page_options, true) ? $default_per_page : $per_page_options[0];
+ }
+
+ /**
+ * LIKE 検索用にワイルドカード文字をエスケープする。
+ */
+ private function escapeLikeValue(string $value): string
+ {
+ return str_replace(['\\', '%', '_'], ['\\\\', '\%', '\_'], $value);
+ }
+
/**
* 登録一覧からの編集画面表示
*/
diff --git a/config/forms.php b/config/forms.php
index eb451fe95..5f3b08c0b 100644
--- a/config/forms.php
+++ b/config/forms.php
@@ -2,6 +2,15 @@
return [
+ // 登録一覧設定
+ 'list_inputs' => [
+ // 1ページあたりの表示件数候補
+ 'per_page_options' => [10, 20, 50, 100],
+
+ // 1ページあたりの初期表示件数
+ 'default_per_page' => 10,
+ ],
+
// ファイルアップロード許可設定
'upload' => [
// クライアント拡張子の許可リスト
diff --git a/database/migrations/2026_05_26_000000_add_list_inputs_search_indexes_to_forms_tables.php b/database/migrations/2026_05_26_000000_add_list_inputs_search_indexes_to_forms_tables.php
new file mode 100644
index 000000000..11aa4b606
--- /dev/null
+++ b/database/migrations/2026_05_26_000000_add_list_inputs_search_indexes_to_forms_tables.php
@@ -0,0 +1,40 @@
+index(['forms_id', 'created_at'], 'forms_inputs_forms_id_created_at_index');
+ });
+
+ Schema::table('forms_input_cols', function (Blueprint $table) {
+ $table->index('forms_inputs_id', 'forms_input_cols_forms_inputs_id_index');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('forms_input_cols', function (Blueprint $table) {
+ $table->dropIndex('forms_input_cols_forms_inputs_id_index');
+ });
+
+ Schema::table('forms_inputs', function (Blueprint $table) {
+ $table->dropIndex('forms_inputs_forms_id_created_at_index');
+ });
+ }
+}
diff --git a/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php b/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php
index 572762cc6..f897ce473 100644
--- a/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php
+++ b/resources/views/plugins/user/forms/default/forms_list_inputs.blade.php
@@ -10,6 +10,27 @@
@section("plugin_setting_$frame->id")
+@php
+ $search_condition = $search_condition ?? [
+ 'keyword' => '',
+ 'status' => '',
+ 'created_from' => '',
+ 'created_to' => '',
+ ];
+ $per_page_options = $per_page_options ?? config('forms.list_inputs.per_page_options', []);
+ $view_count = $view_count ?? config('forms.list_inputs.default_per_page');
+ $list_inputs_url = url('/') . "/plugin/forms/listInputs/{$page->id}/{$frame_id}/{$form->id}";
+ $has_search_condition = $search_condition['keyword'] !== ''
+ || $search_condition['status'] !== ''
+ || $search_condition['created_from'] !== ''
+ || $search_condition['created_to'] !== '';
+ $pagination_appends = array_filter($search_condition, function ($value) {
+ return !is_null($value) && $value !== '';
+ });
+ $list_inputs_redirect_query = array_merge($pagination_appends, ["frame_{$frame_id}_page" => 1]);
+ $list_inputs_redirect_path = $list_inputs_url . '?' . http_build_query($list_inputs_redirect_query) . "#frame-{$frame_id}";
+@endphp
+
{{-- 登録後メッセージ表示 --}}
@include('plugins.common.flash_message')
@@ -59,6 +80,41 @@ function submit_register_other_plugins(id) {
})
+
+
{{-- (左側)件数 --}}
@@ -66,6 +122,18 @@ function submit_register_other_plugins(id) {
+ {{-- (右側)表示件数変更 --}}
+
+
{{-- (右側)ダウンロードボタン --}}