diff --git a/app/Admin/Components.php b/app/Admin/Components.php index ebfab98..51a1dd5 100644 --- a/app/Admin/Components.php +++ b/app/Admin/Components.php @@ -100,6 +100,17 @@ class Components extends BaseRenderer { ->accept($accept); } + public function chunkFileControl($name, $label, $accept = '*', $multiple = false){ + return amis()->FileControl($name, $label ?? __('admin.components.files')) + ->multiple($multiple) + ->joinValues(false) + ->useChunk(true) + ->accept($accept) + ->startChunkApi(admin_url('start_chunk_upload_file')) + ->chunkApi(admin_url('save_chunk_upload_file')) + ->finishChunkApi(admin_url('finish_chunk_upload_file')); + } + /** * 标签选择 */ diff --git a/app/Admin/Controllers/ArticleController.php b/app/Admin/Controllers/ArticleController.php index 82f46ef..c6825c1 100644 --- a/app/Admin/Controllers/ArticleController.php +++ b/app/Admin/Controllers/ArticleController.php @@ -90,7 +90,7 @@ class ArticleController extends AdminController amis()->DateTimeControl('published_at', __('admin.articles.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.articles.published_at_remark')), amis()->SwitchControl('is_enable', __('admin.articles.is_enable'))->value(false), amis()->SwitchControl('is_recommend', __('admin.articles.is_recommend'))->value(false), - Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.xsl,.xlsx,.txt,.doc,.docx,.pdf,.pptx', true), + Components::make()->chunkFileControl('appendixes', __('admin.articles.appendixes'), '.xsl,.xlsx,.txt,.doc,.docx,.pdf,.pptx'), ])->md(4), amis()->Wrapper()->body([ Components::make()->fuEditorControl('content', __('admin.articles.content')), diff --git a/app/Admin/routes.php b/app/Admin/routes.php index e53cb36..b080bf1 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -36,4 +36,8 @@ Route::group([ $router->post('upload_file', [\App\Admin\Controllers\IndexController::class, 'uploadFile']); $router->post('upload_image', [\App\Admin\Controllers\IndexController::class, 'uploadImage']); $router->post('upload_rich', [\App\Admin\Controllers\IndexController::class, 'uploadRich']); + + $router->post('start_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'startChunk']); + $router->post('save_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'saveChunk']); + $router->post('finish_chunk_upload_file', [\App\Admin\Controllers\IndexController::class, 'finishChunk']); }); diff --git a/app/Models/Filters/AdFilter.php b/app/Models/Filters/AdFilter.php index a0535ad..5b1e5f6 100644 --- a/app/Models/Filters/AdFilter.php +++ b/app/Models/Filters/AdFilter.php @@ -2,6 +2,7 @@ namespace App\Models\Filters; +use Illuminate\Support\Arr; use EloquentFilter\ModelFilter; class AdFilter extends ModelFilter diff --git a/app/Traits/UploadTrait.php b/app/Traits/UploadTrait.php index 131b91e..074d963 100644 --- a/app/Traits/UploadTrait.php +++ b/app/Traits/UploadTrait.php @@ -3,6 +3,7 @@ namespace App\Traits; use Slowlyo\OwlAdmin\Admin; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Storage; trait UploadTrait @@ -49,7 +50,7 @@ trait UploadTrait } /** - * 存放临时文件目录; + * 存放临时文件目录,按日期区分; */ protected function upload($type = 'file') { @@ -59,7 +60,7 @@ trait UploadTrait return $this->response()->fail(__('admin.upload_file_error')); } - $path = $file->store(Admin::config('admin.upload.tem_directory.' . $type), Admin::config('admin.upload.disk')); + $path = $file->store(Admin::config('admin.upload.tem_directory.' . $type).'/'.date('Y-m-d'), Admin::config('admin.upload.disk')); return $this->response()->success(['value' => $path]); } @@ -116,4 +117,83 @@ trait UploadTrait } return $fileArr; } + + /** + * 开始分片上传, 生成唯一ID + */ + public function startChunk() + { + $type = 'file'; + $fileName = request()->get('filename', ''); + $uploadId = md5(time().$fileName); + + //创建临时文件夹 + if ( Storage::disk(Admin::config('admin.upload.disk'))->exists(Admin::config('admin.upload.tem_directory.' . $type).'/'.$uploadId) === false ) { + if ( Storage::disk(Admin::config('admin.upload.disk'))->makeDirectory(Admin::config('admin.upload.tem_directory.' . $type).'/'.$uploadId) === false ) { + return false; + } + } + + return $this->response()->success(['uploadId' => $uploadId]); + } + + /** + * 保存分片 + */ + public function saveChunk() + { + $type = 'file'; + + $file = request()->file('file'); + $uploadId = request()->get('uploadId'); + $partNumber = request()->get('partNumber'); + $partSize = request()->get('partSize'); + // dd($file); + $fileName = $file->getClientOriginalName(); + + //判断该分片是否已存在, + $dirPath = Admin::config('admin.upload.tem_directory.' . $type).'/'.$uploadId; + if(Storage::disk(Admin::config('admin.upload.disk'))->exists($dirPath . '/'.$fileName.'_'.$partNumber)){ + return $this->response()->fail(__('admin.upload_file_error')); + }else{ + //验证分片大小-todo + $path = $file->storeAs($dirPath, $fileName.'_'.$partNumber, Admin::config('admin.upload.disk')); + $realPath = Storage::disk(Admin::config('admin.upload.disk'))->url($path); + $eTag = md5_file($realPath); + return $this->response()->success(['eTag' => $eTag]); + } + } + + /** + * 完成分片 + */ + public function finishChunk() + { + $type = 'file'; + //合并文件 + $fileName = request()->get('filename', ''); + $uploadId = request()->get('uploadId', ''); + $partList = request()->get('partList', []); + + $basePath = Admin::config('admin.upload.tem_directory.' . $type).'/'.$uploadId; + $realPath = 'chunk/'.$fileName; + + //获取分片列表中序号,查看分片是否都完成上传 + $partNumberList = Arr::pluck($partList, 'partNumber'); + + if(max($partNumberList) === count($partNumberList)){ + for($i = 1; $i<=count($partNumberList); $i++){ + $_file = Storage::disk(Admin::config('admin.upload.disk'))->get($basePath.'/'.$fileName.'_'.$i); + Storage::disk(Admin::config('admin.upload.disk'))->append($realPath, $_file, null); + } + //删除分片文件夹 + Storage::disk(Admin::config('admin.upload.disk'))->deleteDirectory($basePath); + + $value = Storage::disk(Admin::config('admin.upload.disk'))->url($realPath); + + return $this->response()->success(['value'=>$value]); + }else{ + return $this->response()->fail(__('admin.upload_file_error')); + } + } } \ No newline at end of file