laravel-admin 恶心的图片上传功能,让广大开发者很是苦恼,今天分享一个 手动改为异步传图的完整方案给大家,如果有大神在,也可以考虑将其封装为扩展 ~
同时也分享一下列表使用 tab 的解决方案 ~ 以及如何使用 JSON 方式存储动态性字段比较强的类型的数据 ~
话不多,看代码
grid()控制器
protected function grid()
{
$grid = new Grid(new Ad());
$grid->column('id', __('广告编号'))->sortable();;
//$grid->column('group', __('广告位置'));
$grid->column('value', __('广告信息'));
$grid->column('status', __('广告状态'))->radio(Ad::STATUS);
//$grid->column('created_at', __('创建时间'));
//$grid->column('updated_at', __('最后更新'));
//return $grid;
$tab = new Tab();
$tabs = Ad::GROUP;
$tab_type = request('tab_type', 1);
$grid->disableCreateButton();//禁用默认的推荐按钮
foreach ($tabs as $key => $value) {
if ($tab_type == $key) {
$grid->model()->where('group', $key);
$grid->tools(function ($tools)use($key,$value) {
$url = "ads/create?group={$key}";
$icon = "fa fa-plus";
$text = "新建{$value}";
$tools->append(new ShowArtwork($url,$icon,$text));
});
$tab->add($value, $grid->render(), true);
}else {
$tab->addLink($value,'?tab_type='.$key);
}
}
return $tab;
}
form()控制器代码
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$form = new Form(new Ad());
$form->saving(function (Form $form) {//保存数据前,合并一下value
$original = $form->model()->value ?? [];// 原数据
$now = $form->value;// 表单数据
$merge = array_merge($original,$now);// 合并数据
//echo "requset:";dump(request()->all());
// 根据model->value配置的字段处理数据
$groupInfo = Ad::GROUPINFO[$form->model()->group??request('group',1)];
$groupInfo = array_merge(Ad::GROUPALL,$groupInfo);
//dump($groupInfo);
foreach ($groupInfo as $mk => $mv){
try{
$key = strstr($mk, '_tmp',true);
if(!$key){//_tmp结尾的字段为图片上传字段不需要保存
$file_key = $mk . '_upload_file';
$file = Session::get($file_key);
if($file){// 判断session中有没有图片
// 删除原图
$disk = QiniuStorage::disk('qiniu');
if(isset($merge[$mk]) && $file['key'] != $merge[$mk])//避免传的新图和老图是同一张
$disk->delete($merge[$mk]);
// 存储新图
$merge[$mk] = $file['key'];
Session::forget($file_key);
}
$endValue[$mk] = $merge[$mk]??'';
}
} catch (\Exception $exception ){
dd($exception);
}
}
//dd($endValue);
$form->value = $endValue;
});
//$form->radio('group', __('广告位置'))->options(Ad::GROUP)->default(1);
$form->hidden('group')->default(request('group',1));
$form->display('group', __('广告位置'))->with(function ($group) {
return '' . Ad::GROUP[$group?:request('group',1)] . '';
});
//$form->text('value', __('广告信息'));
$form->embeds('value', '广告信息', function ($em_form) use($form) {
$groupInfo = Ad::GROUPINFO[$form->model()->group??request('group',1)];
$groupInfo = array_merge(Ad::GROUPALL,$groupInfo);
foreach ($groupInfo as $gik => $giv){
$type = $giv[0];
switch ($type){
case 'image' :
case 'file' :
$em_form->$type($gik,$giv[1]??$gik)->rules($giv[2]??'')->removable()
->options(
[
'showPreview' => true,
//'allowedFileExtensions'=>['apk'],
'showUpload' => false,
'uploadAsync' => true,
'uploadUrl' => '/admin/upload_file',
'uploadExtraData' => [
'_token' => csrf_token(),
'_method' => 'POST',
'dir' => 'ads',//保存路径
'file_field' => "value.{$gik}",//文件存放字段
],
]
);
break;
case 'multipleImage' :
case 'multipleFile' :
$em_form->$type($gik,$giv[1]??$gik)->rules($giv[2]??'')->sortable()->removable();
break;
case 'display' :
$config = config("filesystems.disks.qiniu");
$em_form->$type($gik,$giv[1]??$gik)->rules($giv[2]??'')->with(function ($value) use($config) {
if($value)
return "";
});
break;
case 'radio' :
$em_form->$type($gik,$giv[1]??$gik)->rules($giv[2]??'')
->options($giv[4])->default(1);
break;
default:
$em_form->$type($gik,$giv[1]??$gik)->rules($giv[2]??'')->attribute($giv[3]??[]);;
}
}
});
$form->switch('status', __('广告状态'))->default(1)->rules();
return $form;
}
Ad 的 Model 类
'开屏广告',
2 => '首页幻灯',
3 => '首页滚动',
4 => '首页推荐',
5 => '首页大图',
];
const GROUPALL = [
'title'=>[
'text', '标题', 'required',['required' => '1']
],
'type'=>[
'radio', '类型', 'required',['required' => '1'],['1' => '外链', '2'=> '信息详情']
],
'url'=>[
'text', '链接', 'required',['required' => '1']
]
];
const GROUPINFO = [// 广告位字段配置
1 => [
// 'title'=>[
// 'text', '标题', 'required',['required' => '1']
// ],
'image'=>[// _tmp为固定必加后缀,实际上字段为image
'display', '图片预览', ''
],
'image_tmp'=>[// _tmp为固定必加后缀,实际上字段为image
'image', '替换图片', ''
],
// 'url'=>[
// 'text', '链接', 'required',['required' => '1']
// ]
],
2 => [
// 'title'=>[
// 'text', '标题', 'required',['required' => '1']
// ],
'image'=>[// _tmp为固定必加后缀,实际上字段为image
'display', '图片预览', ''
],
'image_tmp'=>[// _tmp为固定必加后缀,实际上字段为image
'image', '替换图片', ''
],
// 'url'=>[
// 'text', '链接', 'required',['required' => '1']
// ]
],
3 => [
],
4 => [
// 'title'=>[
// 'text', '标题', 'required',['required' => '1']
// ],
'image'=>[// _tmp为固定必加后缀,实际上字段为image
'display', '图片预览', ''
],
'image_tmp'=>[// _tmp为固定必加后缀,实际上字段为image
'image', '替换图片', ''
],
// 'url'=>[
// 'text', '链接', 'required',['required' => '1']
// ]
],
5 => [
// 'title'=>[
// 'text', '标题', 'required',['required' => '1']
// ],
'image'=>[// _tmp为固定必加后缀,实际上字段为image
'display', '图片预览', ''
],
'image_tmp'=>[// _tmp为固定必加后缀,实际上字段为image
'image', '替换图片', ''
],
// 'url'=>[
// 'text', '链接', 'required',['required' => '1']
// ]
],
];
const STATUS = [
'0' => '隐藏',
'1' => '显示',
];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'group', 'value', 'status',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
];
protected $casts = [
'value' => 'json',
];
}
上传文件的控制器/admin/upload_file
/**
* 上传文件到七牛
* @param Request $request [description]
* @return [type][description]
*/
public function uploadFile(Request $request)
{
$dir = $request->input('dir','images');
$file_field = $request->input('file_field');
// 判断是否有文件上传
if ($request->hasFile($file_field)) {
// 获取文件,file对应的是前端表单上传input的name
$file = $request->file($file_field);
$extension = $file->getClientOriginalExtension();
// 初始化
$disk = QiniuStorage::disk('qiniu');
// 重命名文件
//$fileName = md5($file->getClientOriginalName().time().rand()).'.'.$extension;
//$fileName = $file->getClientOriginalName();//使用原文件名
$fileName = md5_file($file->getRealPath()).'.'.$extension;//用md5值
// 上传到七牛
$bool = $disk->put($dir.'/'.$fileName,file_get_contents($file->getRealPath()));
// 判断是否上传成功
if ($bool) {
$data['key'] = $dir.'/'.$fileName;
$data['url'] = $disk->downloadUrl($data['key']);
$data['type'] = $extension;
//$data['md5'] = $disk->avInfo($data['key']);
$file_key = strstr(substr(strrchr($file_field,'.'),1), '_tmp',true) . '_upload_file';
Session::put($file_key, $data);
return Response::json(['success' => "true", 'message' => "上传成功", "data" => $data]);
}
return Response::json(['success' => "false", 'message' => "上传失败"],401);
}
return Response::json(['success' => "false", 'message' => "没有文件"],401);
}
简单说一下异步传图实现方案,也是同事传授的方法,使用 seesion 缓存传上来的图
这里我根据字段名称进行了缓存,看代码
$file_key = strstr(substr(strrchr($file_field,'.'),1), '_tmp',true) . '_upload_file';
然后在控制器层再将它读出来使用。。。
由于 JSON 方式传图字段每次提交都会报错,索性只要是图文的字段就必须两个一个真实字段,一个是上传图片的临时字段例如:image_tmp,数据库中并不保存该值
总之方案也不是很完美,如果你也要解决这恶心的事情,可以优化一下,或者分享更好的方案 ~
也可以使用 js 解决方案
$this->script = script;
🐶 你走,我不送你。你来,风雨无阻,我去接你。