遗忘悠剑

🍀 记录精彩的程序人生 开始使用

laravel-admin 恶心的图片上传功能改为异步传图的完整方案

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;

🐶 你走,我不送你。你来,风雨无阻,我去接你。

评论
留下你的脚步