実装概要
FastAdmin の管理画面において、既存のリストデータに対して独自の業務フローを組み込む場合があります。今回は、「編集」ボタンの前に「審査(承認)」機能を追加し、選択したレコードをステータス更新する処理を実装します。
1. 言語キーの定義
まず、フロントエンドに表示されるラベル用に、必要な文字列を言語定義ファイルに追加します。この例では、動画(video)モジュールに関する設定を行います。
以下のパスにあるファイルを開き、新しい翻訳キーを追加してください。
application/admin/lang/zh-cn/video.php
'Status' => 'ステータス',
'Audit Reason' => '審査理由',
'Review' => '審査',
// ... existing lines
2. コントローラー側の処理追加
バックエンドでデータの保存を行う処理を作成します。基本的には既存の「編集」アクションと同様の構造を持ちますが、受け付けるパラメータを絞り込むため、一部フィールドの制限を加えます。ここでは元の関数名から独自の名前に変更しています。
コントローラーファイル:application/admin/controller/Video.php
public function review($id = null)
{
// レコードの取得
$row = $this->model->find($id);
if (!$row) {
$this->error(__('No Data Found'));
}
// データ権限の制限チェック
$allowedAdminIds = $this->getDataLimitAdminIds();
if (is_array($allowedAdminIds)) {
if (!in_array($row[$this->dataLimitField], $allowedAdminIds)) {
$this->error(__('Access Denied'));
}
}
if ($this->request->isPost()) {
$updateData = $this->request->post("row/a");
if ($updateData) {
$updateData = $this->preExcludeFields($updateData);
$saveResult = false;
Db::startTrans();
try {
// バリデーションモデルの適用
if ($this->modelValidate) {
$modelName = str_replace("\\model\\", "\\validate\\", get_class($this->model));
$validateRule = is_bool($this->modelValidate)
? ($this->modelSceneValidate ? $modelName . '.edit' : $modelName)
: $this->modelValidate;
$row->validateFailException(true)->validate($validateRule);
}
// フィールドを指定して保存(許可されたフィールドのみ)
$saveResult = $row->allowField(['reason', 'status'])->save($updateData);
Db::commit();
} catch (\think\exception\ValidateException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (\PDOException $e) {
Db::rollback();
$this->error($e->getMessage());
} catch (\Exception $e) {
Db::rollback();
$this->error($e->getMessage());
}
if ($saveResult !== false) {
$this->success();
} else {
$this->error(__('Update Failed'));
}
}
$this->error(__('Parameter Invalid'));
}
$this->view->assign("dataRow", $row);
return $this->view->fetch();
}
3. ビューテンプレートの作成
入力フォームの画面を新規作成します。ここでの注意点は、タイトルなどの参照すべき情報を読み取り専用(readonly)にし、変更が必要なフィールド(理由やステータス)だけを入力可能にすることです。
ファイルパス:application/admin/view/video/review.html
<form id="review-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Subject')}:</label>
<div class="col-xs-12 col-sm-8">
{$dataRow.title|htmlentities}
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Audit Reason')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="input-reason" class="form-control" name="row[reason]" type="text" value="{$dataRow.reason|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Approval Status')}:</label>
<div class="col-xs-12 col-sm-8">
<select id="select-status" class="form-control" name="row[status]">
<option value="0" {$dataRow.status == 0 ? 'selected' : ''}>Rejected</option>
<option value="1" {$dataRow.status == 1 ? 'selected' : ''}>Approved</option>
</select>
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed ">{:__('Submit')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Clear')}</button>
</div>
</div>
</form>
4. フロントエンドテーブルの設定
最後に、管理一覧表のJavaScript設定を変更し、新たな操作ボタンを表示します。これにより、各データ行に対して「審査」ポップアップがトリガーされます。
対象ファイル:public/assets/js/backend/video.js
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var MainController = {
init: function () {
// テーブル API の拡張設定
Table.api.init({
extend: {
index_url: 'video/index' + location.search,
add_url: 'video/add',
edit_url: 'video/edit',
review_url: 'video/review', // カスタム URL を追加
del_url: 'video/del',
multi_url: 'video/multi',
table: 'video',
}
});
var dataTable = $("#list-table");
// テーブルの初期化
dataTable.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'id',
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id')},
{field: 'title', title: __('Subject')},
{field: 'create_time', title: __('Create Time')},
{field: 'status', title: __('Current Status')},
{field: 'operate', title: __('Actions'), table: dataTable,
buttons: [
// 新しいボタン定義
{name: 'verify', text: __('Review'), icon: 'fa fa-check', classname: 'btn btn-xs btn-warning btn-dialog', url: 'video/review'}
],
events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
Table.api.bindevent(dataTable);
},
verify: function () {
// ページ遷移時のイベントバインド確保
MainController.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
}
}
};
return MainController;
});