Dcat Admin 自定义 Form 表单实现后台系统配置内容的自定义,并可扩展配置项。

Laravel框架
1369
0
0
2022-09-19

配置演示

可配置项目代码Gitee地址

起因

  • 之前在做项目的时候,后台管理扩展使用的是 Laravel-Admin,需要在后台可以灵活添加和修改一些项目需求的配置。然后我在 Github 上搜索了相关扩展,当时找到了这个 Config manager for laravel-admin。这个确实解决了我的燃眉之急,只不过这个配置比较简单,就是 key => value 的配置,而且 value 的值也只是一个 text 类型的 input 框,不能使用时间区、下拉框、选择按钮、上传图片等控件。页面效果如下:

Dcat Admin 自定义 Form 表单实现后台系统配置内容的自定义

  • 当时心想我怎么实现灵活的添加配置,并且可以任意的使用 form 表单控件,想了好久还是没有好的办法。这件事情一直搁在心里,直到最近才把它给做出来。

灵感

  • 最近项目后台管理扩展使用的是 Dcat Admin,这个是基于 Laravel-Admin 的二次开发的,使用起来几乎没有障碍。UI界面比原先 Laravel-Admin 的要好看,所以就用它了。
  • 这次我还是需要在后台做可灵活添加的配置,然后我就看 Dcat Admin 的文档和演示案例。突然发现了一个页面是我想要的效果。页面如下

Dcat Admin 自定义 Form 表单实现后台系统配置内容的自定义

  • 然后我就获取了页面的预览代码,分析了一下。得出这个控制器里面有三个主要的方法,一个是 index(),另外两个是 form1()form2()。大概意思就是通过 tab栏 的选择来控制显示对应的表单页面。index 方法默认显示的是 form1 的页面。
  • 虽然这个预览的代码显示的是两个 form 表单页面,但是只要你愿意,它还可以增加的新的表单,它的可扩展性是我所看重的一个点。
<?php
namespace App\Admin\Controllers;
...
class FormController extends Controller
{
// 首页
public function index(Content $content)
{
...
$content->row(function (Row $row) {
$type = request('_t', 1);
$tab = new Tab();
if ($type == 1) {
$tab->add('Form-1', $this->form1());
$tab->addLink('Form-2', request()->fullUrlWithQuery(['_t' => 2]));
} else {
$tab->addLink('Form-1', request()->fullUrlWithQuery(['_t' => 1]));
$tab->add('Form-2', $this->form2(), true);
}
$row->column(12, $tab->withCard());
});
return $content->header('Form');
}
// 表单一
protected function form1()
{
...
}
// 表单二
protected function form2()
{
...
}
}
Dcat Admin 有办法给 $form->dateRange(‘column’)、 $form->timeRange(‘column’) 等区间组件设置默认值么?use Dcat\Admin\Form;
//use Dcat\Admin\Widgets\Form;

不过还有一个问题就是,use Dcat\Admin\Form; 默认有一个 header 头,把它隐藏就行。

Dcat Admin 自定义 Form 表单实现后台系统配置内容的自定义

$form = new Form();
$form->disableHeader(); // 隐藏 header
  • 我这边为了存入的数据在页面上展示,统一使用了 Form 表单的 default() 方法进行设置的。
$form = new Form();
$form->text('config_one.text', '标题')->required()->default(Arr::get($configArr, 'text'));
// 区间时间选择框的配置
$form->dateRange('config_one.date-start', 'config_one.date-end', '日期区间1')->default([
'start' => Arr::get($configArr, 'date-start'),
'end' => Arr::get($configArr, 'date-end'),
]);
  • 接下来的是,表单提交的方法:
<?php
namespace App\Admin\Controllers;
// 引入上传文件的 Trait
use Dcat\Admin\Form\Field\UploadField;
//use Dcat\Admin\Http\Controllers\AdminController;
// 引入后台基类控制器——>代替AdminController成为当前类继承的父类。
use Illuminate\Routing\Controller;
class SystemConfigController extends Controller
{
use UploadField; // 引入这个上传文件的 Trait
/**
* 配置提交
* @return JsonResponse|mixed
*/
public function store()
{
// 获取请求过来的值
$request = request();
if (empty($allData = $request->all())) {
return JsonResponse::make()->error('没有数据提交!');
}
if ($request->hasFile('_file_')) {
try {
// 如果有图片传入 或者 如果有文件传入
return $this->upload($request->file('_file_'));
} catch (\Exception $e) {
return JsonResponse::make()->error('上传失败:' . $e->getMessage());
}
}
// 循环数据
foreach ($allData as $k => $v) {
if (!in_array($k, array_keys(self::CONFIG_TYPE))) {
continue;
}
SystemConfig::query()->updateOrCreate(['name' => $k], ['name' => $k, 'value' => json_encode($v)]);
}
return JsonResponse::make()->success('提交成功!')->refresh();
}
}
  • 这里面除了文件和图片的上传需要单独处理,其他的正常入库就行。

Dcat Admin 自定义 Form 表单实现后台系统配置内容的自定义

Dcat Admin 自定义 Form 表单实现后台系统配置内容的自定义

  • 因为我这个 Form 表单是自定义的,里面的文件上传请求的还是控制器的 store() 方法,因为我重写了 store() 方法,我的方法中没有对应的文件上传的处理,然后我就根据编辑器的 Ctrl + 点击 进入到源代码中,查找图片上传的逻辑代码。
// 原先 AdminController 基类里面的 store 方法
public function store()
{
return $this->form()->store();
}
protected function form()
{
// (Ctrl + 点击)这个 Form 进去找 image 的图片上传的处理方法
return Form::make(new User(), function (Form $form){
...
});
}
  • 源代码的内容:vendor\dcat\laravel-admin\src\Form.php 找到 image 和 file 的配置:
protected static $availableFields = [
...
'file' => Field\File::class,
'image' => Field\Image::class,
...
]
  • 点击进 Field\Image::class 类中,里面有 prepareFile()方法:
/**
* @param UploadedFile $file
*/
protected function prepareFile(UploadedFile $file)
{
$this->callInterventionMethods($file->getRealPath(), $file->getMimeType());
$this->uploadAndDeleteOriginalThumbnail($file);
}
  • 然后我点击 prepareFile() 方法,看哪里使用了,结果就找到了 \vendor\dcat\laravel-admin\src\Form\Field\UploadField.php 这个文件,里面有一个 upload() 方法,这个就是上传图片和文件走的方法。
public function upload(UploadedFile $file)
{
$request = request();
$id = $request->get('_id');
if (! $id) {
return $this->responseErrorMessage('Missing id');
}
if ($errors = $this->getValidationErrors($file)) {
return $this->responseValidationMessage($errors);
}
$this->name = $this->getStoreName($file);
$this->renameIfExists($file);
$this->prepareFile($file);
if (! is_null($this->storagePermission)) {
$result = $this->getStorage()->putFileAs($this->getDirectory(), $file, $this->name, $this->storagePermission);
} else {
$result = $this->getStorage()->putFileAs($this->getDirectory(), $file, $this->name);
}
if ($result) {
$path = $this->getUploadPath();
$url = $this->objectUrl($path);
// 上传成功
return $this->responseUploaded($this->saveFullUrl ? $url : $path, $url);
}
// 上传失败
throw new UploadException(trans('admin.uploader.upload_failed'));
}
  • use Dcat\Admin\Form\Field\UploadField; 这个引用很重要,文件上传需要这个引用。(费好大劲翻源码找到的方法)但是它有个 destroy 方法和 AdminController 控制器的冲突了。到最后我取消继承 AdminController 控制器改为 Controller 控制器了。

结束

  • 到此为止,这个后台可配置的逻辑已经写完了。
  • 不过还可以在 SystemConfig 模型增加配置的调用,将常用的配置缓存到 Redis 中,这样可以任意的在程序里面快速的调用配置了。不过需要注意的是,后台配置修改,要清理 Redis 缓存中配置才行。