瀏覽代碼

修改文件上传处理

邹景立 3 年之前
父節點
當前提交
eb3be52849
共有 3 個文件被更改,包括 83 次插入87 次删除
  1. 11 12
      app/admin/controller/api/Upload.php
  2. 63 61
      app/admin/view/api/upload.js
  3. 9 14
      public/static/admin.js

+ 11 - 12
app/admin/controller/api/Upload.php

@@ -110,7 +110,6 @@ class Upload extends Controller
     /**
      * 文件上传入口
      * @login true
-     * @return Json
      * @throws \think\db\exception\DataNotFoundException
      * @throws \think\db\exception\DbException
      * @throws \think\db\exception\ModelNotFoundException
@@ -118,15 +117,15 @@ class Upload extends Controller
     public function file(): Json
     {
         if (!($file = $this->getFile())->isValid()) {
-            return json(['uploaded' => false, 'error' => ['message' => '文件上传异常,文件过大或未上传!']]);
+            $this->error('文件上传异常,文件过大或未上传!');
         }
         $extension = strtolower($file->getOriginalExtension());
         [$pathname, $original] = [$file->getPathname(), $file->getOriginalName()];
         if (!in_array($extension, str2arr(sysconf('storage.allow_exts')))) {
-            return json(['uploaded' => false, 'error' => ['message' => '文件类型受限,请在后台配置规则!']]);
+            $this->error('文件类型受限,请在后台配置规则!');
         }
         if (in_array($extension, ['sh', 'asp', 'bat', 'cmd', 'exe', 'php'])) {
-            return json(['uploaded' => false, 'error' => ['message' => '文件安全保护,可执行文件禁止上传!']]);
+            $this->error('文件安全保护,可执行文件禁止上传!');
         }
         [$this->type, $this->safe] = [$this->getType(), $this->getSafe()];
         $this->name = input('key') ?: Storage::name($pathname, $extension, '', 'md5_file');
@@ -138,26 +137,26 @@ class Upload extends Controller
                 $info = $local->info($this->name, $this->safe, $original);
                 if (in_array($extension, ['jpg', 'gif', 'png', 'bmp', 'jpeg', 'wbmp'])) {
                     if ($this->imgNotSafe($distname) && $local->del($this->name)) {
-                        return json(['uploaded' => false, 'error' => ['message' => '图片未通过安全检查!']]);
+                        $this->error('图片未通过安全检查!');
                     }
                     [$width, $height] = getimagesize($distname);
                     if (($width < 1 || $height < 1) && $local->del($this->name)) {
-                        return json(['uploaded' => false, 'error' => ['message' => '读取图片的尺寸失败!']]);
+                        $this->error('读取图片的尺寸失败!');
                     }
                 }
             } else {
                 $bina = file_get_contents($pathname);
                 $info = Storage::instance($this->type)->set($this->name, $bina, $this->safe, $original);
             }
+            if (isset($info['url'])) {
+                $this->success('文件上传成功!', ['url' => $this->safe ? $this->name : $info['url']]);
+            } else {
+                $this->error('文件处理失败,请稍候再试!');
+            }
         } catch (HttpResponseException $exception) {
             throw $exception;
         } catch (\Exception $exception) {
-            return json(['uploaded' => false, 'error' => ['message' => $exception->getMessage()]]);
-        }
-        if (is_array($info) && isset($info['url'])) {
-            return json(['uploaded' => true, 'filename' => $this->name, 'url' => $this->safe ? $this->name : $info['url']]);
-        } else {
-            return json(['uploaded' => false, 'error' => ['message' => '文件处理失败,请稍候再试!']]);
+            $this->error($exception->getMessage());
         }
     }
 

+ 63 - 61
app/admin/view/api/upload.js

@@ -1,59 +1,59 @@
 define(['md5'], function (SparkMD5, allowMime) {
     allowMime = JSON.parse('{$exts|raw}');
-    return function (element, callable, option) {
+    return function (element, callable, completeCallable) {
         /*! 初始化变量 */
-        option = {element: $(element), exts: [], mimes: [], files: {}, cache: {}, load: 0};
-        option.count = {total: 0, uploaded: 0}, option.size = option.element.data('size') || 0;
-        option.safe = option.element.data('safe') ? 1 : 0, option.hload = option.element.data('hide-load') ? 1 : 0;
-        option.field = option.element.data('field') || 'file', option.input = $('[name="_field_"]'.replace('_field_', option.field));
-        option.uptype = option.safe ? 'local' : option.element.attr('data-uptype') || '', option.multiple = option.element.data('multiple') > 0;
+        var opt = {element: $(element), exts: [], mimes: [], files: {}, cache: {}, load: 0};
+        opt.count = {total: 0, uploaded: 0}, opt.size = opt.element.data('size') || 0;
+        opt.safe = opt.element.data('safe') ? 1 : 0, opt.hload = opt.element.data('hide-load') ? 1 : 0;
+        opt.field = opt.element.data('field') || 'file', opt.input = $('input[name="' + opt.field + '"]:not([type=file])');
+        opt.uptype = opt.safe ? 'local' : opt.element.attr('data-uptype') || '', opt.multiple = opt.element.data('multiple') > 0;
         /*! 文件选择筛选 */
-        $((option.element.data('type') || '').split(',')).map(function (i, ext) {
-            if (allowMime[ext]) option.exts.push(ext), option.mimes.push(allowMime[ext]);
+        $((opt.element.data('type') || '').split(',')).map(function (i, ext) {
+            if (allowMime[ext]) opt.exts.push(ext), opt.mimes.push(allowMime[ext]);
         });
         /*! 初始化上传组件 */
-        option.uploader = layui.upload.render({
+        opt.uploader = layui.upload.render({
             url: '{:url("admin/api.upload/file")}',
-            auto: false, elem: element, accept: 'file', multiple: option.multiple,
-            exts: option.exts.join('|'), acceptMime: option.mimes.join(','), choose: function (object) {
-                option.element.triggerHandler('upload.choose', option.files = object.pushFile());
-                option.uploader.config.elem.next().val(''), layui.each(option.files, function (index, file) {
-                    if (option.size > 0 && file.size > option.size) {
-                        return delete option.files[index], $.msg.tips('文件大小超出上传限制!');
+            auto: false, elem: element, accept: 'file', multiple: opt.multiple,
+            exts: opt.exts.join('|'), acceptMime: opt.mimes.join(','), choose: function (object) {
+                opt.element.triggerHandler('upload.choose', opt.files = object.pushFile());
+                opt.uploader.config.elem.next().val(''), layui.each(opt.files, function (index, file) {
+                    if (opt.size > 0 && file.size > opt.size) {
+                        return delete opt.files[index], $.msg.tips('文件大小超出上传限制!');
                     }
-                    option.load = option.hload || $.msg.loading('上传进度 <span data-upload-progress>0%</span>');
-                    option.count.total++, file.index = index, option.cache[index] = file, delete option.files[index];
+                    opt.load = opt.hload || $.msg.loading('上传进度 <span data-upload-progress>0%</span>');
+                    opt.count.total++, file.index = index, opt.cache[index] = file, delete opt.files[index];
                     md5file(file).then(function (file) {
-                        option.element.triggerHandler('upload.hash', file);
+                        opt.element.triggerHandler('upload.hash', file);
                         jQuery.ajax("{:url('admin/api.upload/state')}", {
-                            data: {key: file.xkey, uptype: option.uptype, safe: option.safe, name: file.name}, method: 'post', success: function (ret) {
+                            data: {key: file.xkey, uptype: opt.uptype, safe: opt.safe, name: file.name}, method: 'post', success: function (ret) {
                                 if (parseInt(ret.code) === 404) {
                                     file.xurl = ret.data.url;
-                                    option.uploader.config.url = ret.data.server;
-                                    option.uploader.config.data.key = ret.data.key;
-                                    option.uploader.config.data.safe = ret.data.safe;
-                                    option.uploader.config.data.uptype = ret.data.uptype;
+                                    opt.uploader.config.url = ret.data.server;
+                                    opt.uploader.config.data.key = ret.data.key;
+                                    opt.uploader.config.data.safe = ret.data.safe;
+                                    opt.uploader.config.data.uptype = ret.data.uptype;
                                     if (ret.data.uptype === 'qiniu') {
-                                        option.uploader.config.data.token = ret.data.token;
+                                        opt.uploader.config.data.token = ret.data.token;
                                     } else if (ret.data.uptype === 'alioss') {
-                                        option.uploader.config.data['policy'] = ret.data.policy;
-                                        option.uploader.config.data['signature'] = ret.data.signature;
-                                        option.uploader.config.data['OSSAccessKeyId'] = ret.data.OSSAccessKeyId;
-                                        option.uploader.config.data['success_action_status'] = 200;
-                                        option.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
+                                        opt.uploader.config.data['policy'] = ret.data.policy;
+                                        opt.uploader.config.data['signature'] = ret.data.signature;
+                                        opt.uploader.config.data['OSSAccessKeyId'] = ret.data.OSSAccessKeyId;
+                                        opt.uploader.config.data['success_action_status'] = 200;
+                                        opt.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
                                     } else if (ret.data.uptype === 'txcos') {
-                                        option.uploader.config.data['q-ak'] = ret.data['q-ak'];
-                                        option.uploader.config.data['policy'] = ret.data.policy;
-                                        option.uploader.config.data['q-key-time'] = ret.data['q-key-time'];
-                                        option.uploader.config.data['q-signature'] = ret.data['q-signature'];
-                                        option.uploader.config.data['q-sign-algorithm'] = ret.data['q-sign-algorithm'];
-                                        option.uploader.config.data['success_action_status'] = 200;
-                                        option.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
+                                        opt.uploader.config.data['q-ak'] = ret.data['q-ak'];
+                                        opt.uploader.config.data['policy'] = ret.data.policy;
+                                        opt.uploader.config.data['q-key-time'] = ret.data['q-key-time'];
+                                        opt.uploader.config.data['q-signature'] = ret.data['q-signature'];
+                                        opt.uploader.config.data['q-sign-algorithm'] = ret.data['q-sign-algorithm'];
+                                        opt.uploader.config.data['success_action_status'] = 200;
+                                        opt.uploader.config.data['Content-Disposition'] = 'inline;filename=' + encodeURIComponent(file.name);
                                     }
                                     object.upload(file.index, file);
                                 } else if (parseInt(ret.code) === 200) {
                                     file.xurl = ret.data.url;
-                                    option.uploader.config.done({uploaded: true, url: file.xurl}, file.index);
+                                    opt.uploader.config.done({code: 1, url: file.xurl, info: '文件秒传成功!'}, file.index);
                                 } else {
                                     $.msg.tips(ret.info || ret.error.message || '文件上传出错!');
                                 }
@@ -63,32 +63,34 @@ define(['md5'], function (SparkMD5, allowMime) {
                 });
             }, progress: function (number) {
                 $('[data-upload-progress]').html(number + '%');
-                option.element.triggerHandler('upload.progress', {number: number, event: arguments[2], file: arguments[3]});
-            }, done: function (ret, index) {
-                option.element.triggerHandler('upload.done', {file: option.cache[index], data: ret});
-                if (++option.count.uploaded >= option.count.total) {
-                    option.element.triggerHandler('upload.complete', {});
-                    option.element.html(option.element.data('html'));
-                    option.hload || $.msg.close(option.load);
-                    option.uploader.reload();
-                }
-                if (typeof ret.code === 'number' && parseInt(ret.code) === 0) {
-                    return $.msg.tips(ret.info || '文件上传失败!');
-                }
-                if (typeof option.cache[index].xurl !== 'string') {
-                    return $.msg.tips('无效的文件对象!');
-                }
-                if (typeof ret.uploaded === 'undefined' && typeof option.cache[index].xurl === 'string') {
-                    ret = {uploaded: true, url: option.cache[index].xurl};
+                opt.element.triggerHandler('upload.progress', {
+                    number: number, event: arguments[2], file: arguments[3]
+                });
+            }, done: function (ret, idx) {
+
+                /*! 检查单个文件上传返回的结果 */
+                if (ret.code < 1) return $.msg.tips(ret.info || '文件上传失败!');
+                if (typeof opt.cache[idx].xurl !== 'string') return $.msg.tips('无效的文件上传对象!');
+
+                /*! 单个文件上传成功结果处理 */
+                if (typeof callable === 'function') {
+                    callable.call(opt.element, opt.cache[idx].xurl, opt.cache['id']);
+                } else {
+                    opt.multiple < 1 && opt.input.val(opt.cache[idx].xurl).trigger('change');
                 }
-                if (ret.uploaded) {
-                    if (typeof callable === 'function') {
-                        callable.call(option.element, ret.url, option.cache[index]);
-                    } else {
-                        option.input.val(ret.url).trigger('change');
+
+                (opt.hload || $.msg.close(opt.load)), opt.element.html(opt.element.data('html'));
+                opt.element.triggerHandler('upload.done', {file: opt.cache[idx], data: ret});
+
+                /*! 所有文件上传完成后结果处理 */
+                if (++opt.count.uploaded >= opt.count.total) {
+                    if (opt.multiple > 0) {
+                        var urls = [];
+                        for (var i in opt.cache) urls.push(opt.cache[i].xurl)
+                        opt.input.val(urls.join('|')).trigger('change');
                     }
-                } else {
-                    $.msg.tips(ret.info || ret.error.message || '文件上传出错!');
+                    opt.element.triggerHandler('upload.complete', {file: opt.cache});
+                    (opt.cache = [], opt.files = []), opt.uploader.reload();
                 }
             }
         });

+ 9 - 14
public/static/admin.js

@@ -191,12 +191,8 @@ $(function () {
                         $(this.elem).val(value).trigger('change');
                     }
                 });
-            }), $dom.find('[data-file]:not([data-inited])').map(function (index, elem, $this, field) {
-                $this = $(elem), field = this.dataset.field || 'file';
-                if (!$this.data('input')) $this.data('input', $('[name="' + field + '"]').get(0));
-                $this.uploadFile(function (url, file) {
-                    $($this.data('input')).data('file', file).val(url).trigger('change');
-                });
+            }), $dom.find('[data-file]:not([data-inited])').map(function () {
+                $(this).uploadFile();
             }), $dom.find('[data-lazy-src]:not([data-lazy-loaded])').each(function () {
                 if (this.dataset.lazyLoaded !== 'true') {
                     if (this.nodeName === 'IMG') {
@@ -531,12 +527,12 @@ $(function () {
     };
 
     /*! 全局文件上传入口 */
-    $.fn.uploadFile = function (callback) {
-        if (this.attr('data-inited')) return false;
-        var that = this, mode = this.attr('data-file') || 'one';
-        this.attr('data-inited', true).attr('data-multiple', (mode !== 'btn' && mode !== 'one') ? 1 : 0);
+    $.fn.uploadFile = function (callable) {
+        if (this.data('inited')) return false;
+        var that = this, mode = this.data('file') || 'one';
+        this.data('inited', true).data('multiple', mode !== 'one' ? 1 : 0);
         require(['upload'], function (apply) {
-            apply.call(this, that, callback);
+            apply.call(this, that, callable);
         });
     };
 
@@ -544,9 +540,8 @@ $(function () {
     $.fn.uploadOneImage = function () {
         return this.each(function ($in, $tpl) {
             $in = $(this), $tpl = $('<a data-file="one" class="uploadimage transition"><span class="layui-icon">&#x1006;</span></a>');
-            $tpl.attr('data-type', $in.data('type') || 'png,jpg,gif').attr('data-size', $in.data('size') || 0);
-            $tpl.attr('data-field', $in.attr('name') || 'image').data('input', this);
-            $tpl.find('span').on('click', function (event) {
+            $tpl.attr('data-size', $in.data('size') || 0).attr('data-type', $in.data('type') || 'png,jpg,gif');
+            $tpl.attr('data-field', $in.attr('name') || 'image').data('input', this).find('span').on('click', function (event) {
                 event.stopPropagation(), $tpl.attr('style', ''), $in.val('');
             });
             $in.attr('name', $tpl.attr('data-field')).after($tpl).on('change', function () {