准备工作
1.在.env文件中添加以下配置:
#七牛云存储需要华南区
QN_YUMING=qn3.dzbfsj.com
QN_ACCESS_KEY=mr7yBWpG
QN_SECRET_KEY=rIZTtUBm3tNCSz
QN_BUCKET=kzhtest
QN_REGION=SCN
QN_ACCESS=public
QN_NOTIFY_URL=
QN_FILE_URL=http://qn3.dzbfsj.com/
2. 安装zgldh/qiniu-laravel-storage
composer require zgldh/qiniu-laravel-storage
3.在config/filesystem.php 里面的 disks数组加上:
'qiniu' => [
'driver' => 'qiniu',
'domains' => [
'default' => env('QN_YUMING'),//你的七牛域名
'https' => env('QN_HTTPS'),//你的HTTPS域名
'custom' => env('QN_ZDYYM'),//你的自定义域名
],
'access_key'=> env('QN_ACCESS_KEY'), //AccessKey
'secret_key'=> env('QN_SECRET_KEY'), //SecretKey
'bucket' => env('QN_BUCKET'), //Bucket名字
'notify_url'=> env('QN_NOTIFY_URL'), //持久化处理回调地址
'access' => env('QN_ACCESS'),////空间访问控制 public 或 private
'region' => env('QN_REGION', 'SCN'), //地区//ECN华东 NCN华北 SCN华南 NA北美 ASG东南亚
'url' => env('QN_FILE_URL'), //填写文件访问根url:http://of8kfibjo.bkt.clouddn.com/
],
到这一步,dcat admin后台就可以使用自带的form->file上传文件到七牛云了。但是,因上传要经过php中转,先上传到服务器,再从服务器上传到七牛,无法上传大文件,且速度很慢。
我们要使用前端直传,最好能切片上传,省去一个步骤,加快上传速度。以下的我试验过的三种方案:
一、最简方案
该方案适合用来上传指定后缀的文件,比如mp4视频。代码如下:
$filename = md5(uniqid()) . '.mp4';// 随机文件名
$disk = Storage::disk('qiniu');
// 回调信息, Dcat 上传文件需要的报文格式
$callBack = [
'status' => true,
'data' => [
'id' => $filename,
'name' => $filename,
'path' => $filename,
'url' => config('filesystems.disks.qiniu.url') . $filename,
],
];
$policy = [
'returnBody' => json_encode($callBack),
];
// 七牛云上传 token
$token = $disk->uploadToken($filename, 3600, $policy);
$form->file('video')->disk('qiniu')->accept('mp4')->autoUpload()->help('仅支持MP4格式')->maxSize(5120000)->removable(false)->url('https://up-cn-east-2.qiniup.com')->options(['fileVal' => 'file'])->on('startUpload', <<<JS
function () {
// 上传文件前附加自定义参数到文件上传接口
const config = {
chunkSize: 5,//切片5MB
forceDirect: true,//全部采用直传
};
this.uploader.options.formData['token'] = "{$token}";
this.uploader.options.formData['fileName'] = "{$filename}";
this.uploader.options.formData['key'] = "{$filename}";
this.uploader.options.formData['config'] = config;
}
JS
);
该方案充分利用了dcat自身的上传功能,不足之处是,只适合上传固定类型的文件,且不支持切片上传,大文件还是容易超时中止上传。
二、扩展表单字段方案
1.新建组件类 app/Admin/Extensions/Form/qnupload.php
<?php
namespace App\Admin\Extensions\Form;
use Dcat\Admin\Form\Field;
class qnupload extends Field
{
protected $view = 'qnupload';
}
2.新建视图文件 resources/views/admin/qnupload.blade.php:
<div class="{{$viewClass['form-group']}}">
<label class="{{$viewClass['label']}} control-label">{{$label}}</label>
<div class="{{$viewClass['field']}}">
@include('admin::form.error')
<div {!! $attributes !!} style="width: 100%; height: 100%;">
<p>{!! $value !!}</p>
<div class="col-md-12">
<div id="container">
<a class="btn btn-default btn-lg " id="pickfiles" href="#" >
<i class="glyphicon glyphicon-plus"></i>
<span>选择文件</span>
</a>
<a class="btn btn-default btn-lg " id="up_load" href="#" >
<span>确认上传</span>
</a>
<a class="btn btn-default btn-lg " id="stop_load" href="#" >
<span>暂停上传</span>
</a>
<a class="btn btn-default btn-lg " id="retry" href="#" >
<span>重试</span>
</a>
</div>
</div>
<div style="display:none" id="success" class="col-md-12">
<div class="alert-success">
队列全部文件处理完毕
</div>
</div>
<div class="col-md-12 ">
<table class="table table-striped table-hover text-left" style="margin-top:40px;display:none">
<thead>
<tr>
<th style="width:50%">文件名</th>
<th style="width:20%">大小</th>
<th style="width:30%">进度</th>
</tr>
</thead>
<tbody id="fsUploadProgress"></tbody>
</table>
</div>
</div>
<div class="qnfile">
<input type="hidden" name="{{$name}}" value="{{ old($column, $value) }}" />
</div>
@include('admin::form.help-block')
</div>
</div>
<!-- script标签加上 "init" 属性后会自动使用 Dcat.init() 方法动态监听元素生成 -->
<script require="@qnupload" init="{!! $selector !!}">
// id 变量是 Dcat.init() 自动生成的,是一个唯一的随机字符串
var uploader = Qiniu.uploader({
disable_statistics_report: true,
makeLogFunc: 1,
runtimes: 'html5,flash,html4',
browse_button: 'pickfiles',
container: 'container',
drop_element: 'container',
max_file_size: '10000mb',
dragdrop: true,
chunk_size: '4mb',
multi_selection: !(moxie.core.utils.Env.OS.toLowerCase()==="ios"),
uptoken: "{{\Storage::disk('qiniu')->uploadToken()}}",
unique_names: true,
max_retries: 7, // 上传失败最大重试次数
domain: "{{config('filesystems.disks.qiniu.url')}}",
get_new_uptoken: true,
auto_start: true,
log_level: 5,
init: {
'BeforeChunkUpload':function (up,file) {
console.log("分块上传文件:",file.name);
},
'FilesAdded': function(up, files) {
$('table').show();
$('#success').hide();
plupload.each(files, function(file) {
console.log('文件类型: ' + file.type);
if(file.type=='image/jpeg'||file.type=='image/jpg'||file.type=='image/png'||file.type=='image/gif' || file.type=='video/x-matroska' || file.type=='video/mp4'){
isUpload =true;
// file.album_name=album_name;
var progress = new FileProgress(file, 'fsUploadProgress');
progress.setStatus("等待...");
progress.bindUploadCancel(up);
}else {
isUpload = false;
up.removeFile(file);
console.log('上传类型只能是.jpg,.png,.gif,.mp4');
return false;
}});
},
'BeforeUpload': function(up, file) {
console.log("开始上传BeforeUpload");
var progress = new FileProgress(file, 'fsUploadProgress');
var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
if (up.runtime === 'html5' && chunk_size) {
progress.setChunkProgess(chunk_size);
}
},
'UploadProgress': function(up, file) {
var progress = new FileProgress(file, 'fsUploadProgress');
var chunk_size = plupload.parseSize(this.getOption('chunk_size'));
progress.setProgress(file.percent + "%", file.speed, chunk_size);
},
'UploadComplete': function() {
$('#success').show();
},
'FileUploaded': function(up, file, info) {
var progress = new FileProgress(file, 'fsUploadProgress');
progress.setComplete(up, info);
},
'Error': function(up, err, errTip) {
$('table').show();
var progress = new FileProgress(err.file, 'fsUploadProgress');
progress.setError();
progress.setStatus(errTip);
}
// ,
// 'Key': function(up, file) {
// var key = "";
// // do something with key
// return key
// }
}
});
uploader.bind('FilesAdded', function() {
console.log("添加了一个文件");
});
uploader.bind('BeforeUpload', function () {
console.log("即将上传");
});
uploader.bind('FileUploaded', function () {
console.log('已上传一个文件');
});
$('#up_load').on('click', function(){
uploader.start();
});
$('#stop_load').on('click', function(){
uploader.stop();
});
$('#retry').on('click', function(){
uploader.stop();
uploader.start();
});
$('#container').on(
'dragenter',
function(e) {
e.preventDefault();
$('#container').addClass('draging');
e.stopPropagation();
}
).on('drop', function(e) {
e.preventDefault();
$('#container').removeClass('draging');
e.stopPropagation();
}).on('dragleave', function(e) {
e.preventDefault();
$('#container').removeClass('draging');
e.stopPropagation();
}).on('dragover', function(e) {
e.preventDefault();
$('#container').addClass('draging');
e.stopPropagation();
});
$('body').on('click', 'table button.btn', function() {
$(this).parents('tr').next().toggle();
});
var getRotate = function(url) {
if (!url) {
return 0;
}
var arr = url.split('/');
for (var i = 0, len = arr.length; i < len; i++) {
if (arr[i] === 'rotate') {
return parseInt(arr[i + 1], 10);
}
}
return 0;
};
</script>
3. 然后注册进 dcat-admin,在 app/Admin/bootstrap.php 中添加以下代码:
// 七牛切片直传
Admin::asset()->alias('@qnupload', [
'js' => [
'/js/qiniu/ui.js',
'/js/qiniu/dist/qiniu.js'
],
'css' => '/css/main.css',
]);
Form::extend('qnfile', qnupload::class);
相关的js,css文件可在七牛官网的demo中找到。
使用方法:$form->qnfile(‘video’);
该方法初步测试,可以实现大文件前端直传,切片上传也正常,不过使用不方便,ui也较难看。