控制台应用,yzncms本身基于tp5.1框架,里面的队列用不了,bug,坑
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

yznUpload.js 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. //封装上传操作 开源自FastAdmin
  2. layui.define(['dropzone', 'yzn','laytpl','notice'], function(exports) {
  3. var $ = layui.$,
  4. laytpl = layui.laytpl,
  5. layer = layui.layer,
  6. yzn = layui.yzn,
  7. Dropzone = layui.dropzone,
  8. notice = layui.notice;
  9. var Upload = {
  10. list: {},
  11. options: {},
  12. config: {
  13. container: document.body,
  14. classname: '.plupload:not([initialized]),.faupload:not([initialized])',
  15. previewtpl: '<li class="file-item thumbnail"><a href="javascript:;"><img data-image onerror="this.src=\'' + yzn.request.fixurl("admin/ajax/icon") + '?suffix={{d.suffix}}\';this.onerror=null;" data-original="{{d.url}}" src="{{d.url}}"><div class="file-panel">{{- d.data.multiple==true ? "<i class=\'iconfont icon-yidong move-picture\'></i>" : "" }} <i class="iconfont icon-tailor cropper" data-input-id="{{d.data.inputId}}"></i> <i class="iconfont icon-trash remove-picture"></i></div></a></li>',
  16. },
  17. events: {
  18. //初始化
  19. onInit: function () {
  20. },
  21. //上传成功的回调
  22. onUploadSuccess: function (up, ret, file) {
  23. var button = up.element;
  24. var onUploadSuccess = up.options.onUploadSuccess;
  25. var data = typeof ret.data !== 'undefined' ? ret.data : ret;
  26. //上传成功后回调
  27. if (button) {
  28. //如果有文本框则填充
  29. var input_id = $(button).data("input-id") ? $(button).data("input-id") : "";
  30. if (input_id) {
  31. var urlArr = [];
  32. var inputObj = $("#" + input_id);
  33. if ($(button).data("multiple") && inputObj.val() !== "") {
  34. urlArr.push(inputObj.val());
  35. }
  36. //var url = Config.upload.fullmode ? Fast.api.cdnurl(data.url) : data.url;
  37. var url = data.url;
  38. urlArr.push(url);
  39. inputObj.val(urlArr.join(",")).trigger("change").trigger("validate");
  40. }
  41. //如果有回调函数
  42. var onDomUploadSuccess = $(button).data("upload-success");
  43. if (onDomUploadSuccess) {
  44. if (typeof onDomUploadSuccess !== 'function' && typeof Upload.api.custom[onDomUploadSuccess] === 'function') {
  45. onDomUploadSuccess = Upload.api.custom[onDomUploadSuccess];
  46. }
  47. if (typeof onDomUploadSuccess === 'function') {
  48. var result = onDomUploadSuccess.call(button, data, ret);
  49. if (result === false)
  50. return;
  51. }
  52. }
  53. }
  54. if (typeof onUploadSuccess === 'function') {
  55. var result = onUploadSuccess.call(button, data, ret);
  56. if (result === false)
  57. return;
  58. }
  59. },
  60. //上传错误的回调
  61. onUploadError: function (up, ret, file) {
  62. var button = up.element;
  63. var onUploadError = up.options.onUploadError;
  64. var data = typeof ret.data !== 'undefined' ? ret.data : ret;
  65. if (button) {
  66. var onDomUploadError = $(button).data("upload-error");
  67. if (onDomUploadError) {
  68. if (typeof onDomUploadError !== 'function' && typeof Upload.api.custom[onDomUploadError] === 'function') {
  69. onDomUploadError = Upload.api.custom[onDomUploadError];
  70. }
  71. if (typeof onDomUploadError === 'function') {
  72. var result = onDomUploadError.call(button, data, ret);
  73. if (result === false)
  74. return;
  75. }
  76. }
  77. }
  78. if (typeof onUploadError === 'function') {
  79. var result = onUploadError.call(button, data, ret);
  80. if (result === false) {
  81. return;
  82. }
  83. }
  84. notice.error({ message: ret.msg.toString().replace(/(<([^>]+)>)/gi, "") + "(code:" + ret.code + ")" });
  85. },
  86. //服务器响应数据后
  87. onUploadResponse: function (response, up, file) {
  88. try {
  89. var ret = typeof response === 'object' ? response : JSON.parse(response);
  90. if (!ret.hasOwnProperty('code')) {
  91. $.extend(ret, {code: -2, msg: response, data: null});
  92. }
  93. } catch (e) {
  94. var ret = {code: -1, msg: e.message, data: null};
  95. }
  96. return ret;
  97. },
  98. //上传全部结束后
  99. onUploadComplete: function (up, files) {
  100. var button = up.element;
  101. var onUploadComplete = up.options.onUploadComplete;
  102. if (button) {
  103. var onDomUploadComplete = $(button).data("upload-complete");
  104. if (onDomUploadComplete) {
  105. if (typeof onDomUploadComplete !== 'function' && typeof Upload.api.custom[onDomUploadComplete] === 'function') {
  106. onDomUploadComplete = Upload.api.custom[onDomUploadComplete];
  107. }
  108. if (typeof onDomUploadComplete === 'function') {
  109. var result = onDomUploadComplete.call(button, files);
  110. if (result === false)
  111. return;
  112. }
  113. }
  114. }
  115. if (typeof onUploadComplete === 'function') {
  116. var result = onUploadComplete.call(button, files);
  117. if (result === false) {
  118. return;
  119. }
  120. }
  121. }
  122. },
  123. api: {
  124. //上传接口
  125. upload: function (element, onUploadSuccess, onUploadError, onUploadComplete) {
  126. element = typeof element === 'undefined' ? Upload.config.classname : element;
  127. $(element, Upload.config.container).each(function () {
  128. if ($(this).attr("initialized")) {
  129. return true;
  130. }
  131. $(this).attr("initialized", true);
  132. var that = this;
  133. var id = $(this).prop("id") || $(this).prop("name") || Dropzone.uuidv4();
  134. var url = $(this).data("url");
  135. var maxsize = $(this).data("maxsize");
  136. var maxcount = $(this).data("maxcount");
  137. var mimetype = $(this).data("mimetype");
  138. var multipart = $(this).data("multipart");
  139. var multiple = $(this).data("multiple");
  140. var type = $(this).data("type");
  141. type = typeof type !== "undefined" ? (type.indexOf('image') > -1 ? 'image':'file'): 'image';
  142. //填充ID
  143. var input_id = $(that).data("input-id") ? $(that).data("input-id") : "";
  144. //预览ID
  145. var preview_id = $(that).data("preview-id") ? $(that).data("preview-id") : "";
  146. //上传URL
  147. url = url ? url : (type == 'image' ? GV.image_upload_url : GV.file_upload_url);
  148. url = yzn.request.fixurl(url);
  149. var chunking = false, chunkSize = typeof GV.site.chunksize !== "undefined" ? GV.site.chunksize :2097152, timeout = 600000;
  150. //最大可上传文件大小
  151. maxsize = typeof maxsize !== "undefined" ? maxsize : (type == 'image' ? GV.site.upload_image_size : GV.site.upload_file_size)+'kb';
  152. //文件类型
  153. mimetype = typeof mimetype !== "undefined" ? mimetype : (type == 'image' ? GV.site.upload_image_ext : GV.site.upload_file_ext);
  154. //请求的表单参数
  155. multipart = typeof multipart !== "undefined" ? multipart : '';
  156. //是否支持批量上传
  157. multiple = typeof multiple !== "undefined" ? multiple : false;
  158. //后缀特殊处理
  159. mimetype = mimetype.split(",").map(function (k) {
  160. return k.indexOf("/") > -1 ? k : (!k || k === "*" || k.charAt(0) === "." ? k : "." + k);
  161. }).join(",");
  162. mimetype = mimetype === '*' ? null : mimetype;
  163. //最大文件限制转换成mb
  164. var maxFilesize = (function (maxsize) {
  165. var matches = maxsize.toString().match(/^([0-9\.]+)(\w+)$/);
  166. var size = matches ? parseFloat(matches[1]) : parseFloat(maxsize),
  167. unit = matches ? matches[2].toLowerCase() : 'b';
  168. var unitDict = {'b': 0, 'k': 1, 'kb': 1, 'm': 2, 'mb': 2, 'gb': 3, 'g': 3, 'tb': 4, 't': 4};
  169. var y = typeof unitDict[unit] !== 'undefined' ? unitDict[unit] : 0;
  170. var bytes = size * Math.pow(1024, y);
  171. return bytes / Math.pow(1024, 2);
  172. }(maxsize));
  173. var options = $(this).data() || {};
  174. options = $.extend(true, {}, options, $(this).data("upload-options") || {});
  175. delete options.success;
  176. delete options.url;
  177. multipart = $.isArray(multipart) ? {} : multipart;
  178. var params = $(this).data("params") || {};
  179. var category = typeof params.category !== 'undefined' ? params.category : ($(this).data("category") || '');
  180. if (category) {
  181. // multipart.category = category;
  182. }
  183. Upload.list[id] = new Dropzone(this, $.extend({
  184. url: url,
  185. params: function (files, xhr, chunk) {
  186. var params = multipart;
  187. if (chunk) {
  188. return $.extend({}, params, {
  189. filesize: chunk.file.size,
  190. filename: chunk.file.name,
  191. chunkid: chunk.file.upload.uuid,
  192. chunkindex: chunk.index,
  193. chunkcount: chunk.file.upload.totalChunkCount,
  194. chunksize: this.options.chunkSize,
  195. chunkfilesize: chunk.dataBlock.data.size,
  196. width: chunk.file.width || 0,
  197. height: chunk.file.height || 0,
  198. type: chunk.file.type,
  199. });
  200. }
  201. return params;
  202. },
  203. chunking: chunking,
  204. chunkSize: chunkSize,
  205. maxFilesize: maxFilesize,
  206. acceptedFiles: mimetype,
  207. maxFiles: (maxcount && parseInt(maxcount) > 1 ? maxcount : (multiple ? null : 1)),
  208. timeout: timeout,
  209. parallelUploads: 1,
  210. previewsContainer: false,
  211. dictDefaultMessage: "将文件拖到此处上载",
  212. dictFallbackMessage: "您的浏览器不支持拖放文件上传",
  213. dictFallbackText: "请使用下面的备用表单像以前一样上传您的文件",
  214. dictFileTooBig: "当前上传({{filesize}}M),最大允许上传文件大小:{{maxFilesize}}M",
  215. dictInvalidFileType: "不允许上传的文件类型",
  216. dictResponseError: "服务端响应(Code:{{statusCode}})",
  217. dictCancelUpload: "取消上传",
  218. dictUploadCanceled: "上传已取消",
  219. dictCancelUploadConfirmation: "确定取消上传?",
  220. dictRemoveFile: "移除文件",
  221. dictMaxFilesExceeded: "你最多允许上传 {{maxFiles}} 个文件",
  222. init: function () {
  223. Upload.events.onInit.call(this);
  224. //必须添加dz-message,否则点击icon无法唤起上传窗口
  225. $(">i", this.element).addClass("dz-message");
  226. this.options.elementHtml = $(this.element).html();
  227. },
  228. sending: function (file, xhr, formData) {
  229. if (typeof file.category !== 'undefined') {
  230. formData.append('category', file.category);
  231. }
  232. },
  233. addedfile: function (file) {
  234. var params = $(this.element).data("params") || {};
  235. var category = typeof params.category !== 'undefined' ? params.category : ($(this.element).data("category") || '');
  236. file.category = typeof category === 'function' ? category.call(this, file) : category;
  237. },
  238. addedfiles: function (files) {
  239. if (this.options.maxFiles && (!this.options.maxFiles || this.options.maxFiles > 1) && this.options.inputId) {
  240. var inputObj = $("#" + this.options.inputId);
  241. if (inputObj.length > 0) {
  242. var value = $.trim(inputObj.val());
  243. var nums = value === '' ? 0 : value.split(/\,/).length;
  244. var remain = this.options.maxFiles - nums;
  245. if (remain === 0 || files.length > remain) {
  246. files = Array.prototype.slice.call(files, remain);
  247. for (var i = 0; i < files.length; i++) {
  248. this.removeFile(files[i]);
  249. }
  250. notice.error({ message: "你最多允许上传 "+this.options.maxFiles+" 个文件" });
  251. }
  252. }
  253. }
  254. },
  255. success: function (file, response) {
  256. var ret = Upload.events.onUploadResponse(response, this, file);
  257. file.ret = ret;
  258. if (ret.code === 1) {
  259. Upload.events.onUploadSuccess(this, ret, file);
  260. } else {
  261. Upload.events.onUploadError(this, ret, file);
  262. }
  263. },
  264. error: function (file, response, xhr) {
  265. var responseObj = $("<div>" + (xhr && typeof xhr.responseText !== 'undefined' ? xhr.responseText : response) + "</div>");
  266. responseObj.find("style, title, script").remove();
  267. var msg = responseObj.text() || '网络错误!';
  268. var ret = {code: 0, data: null, msg: msg};
  269. Upload.events.onUploadError(this, ret, file);
  270. },
  271. uploadprogress: function (file, progress, bytesSent) {
  272. if (file.upload.chunked) {
  273. $(this.element).prop("disabled", true).html("<i class='layui-icon layui-icon-upload'></i> " + '上传' + Math.floor((file.upload.bytesSent / file.size) * 100) + "%");
  274. }
  275. },
  276. totaluploadprogress: function (progress, bytesSent) {
  277. if (this.getActiveFiles().length > 0 && !this.options.chunking) {
  278. $(this.element).prop("disabled", true).html("<i class='layui-icon layui-icon-upload'></i> " + '上传' + Math.floor(progress) + "%");
  279. }
  280. },
  281. queuecomplete: function () {
  282. Upload.events.onUploadComplete(this, this.files);
  283. this.removeAllFiles(true);
  284. $(this.element).prop("disabled", false).html(this.options.elementHtml);
  285. },
  286. chunkSuccess: function (chunk, file, response) {
  287. },
  288. chunksUploaded: function (file, done) {
  289. var that = this;
  290. yzn.request.post({
  291. url: this.options.url,
  292. data: $.extend({}, multipart, {
  293. action: 'merge',
  294. filesize: file.size,
  295. filename: file.name,
  296. chunkid: file.upload.uuid,
  297. chunkcount: file.upload.totalChunkCount,
  298. })
  299. }, function (data, ret) {
  300. done(JSON.stringify(ret));
  301. return false;
  302. }, function (data, ret) {
  303. file.accepted = false;
  304. that._errorProcessing([file], ret.msg);
  305. });
  306. },
  307. onUploadSuccess: onUploadSuccess,
  308. onUploadError: onUploadError,
  309. onUploadComplete: onUploadComplete,
  310. }, Upload.options, options));
  311. //拖动排序
  312. if (preview_id && multiple) {
  313. layui.define('dragsort', function(exports) {
  314. var dragsort = layui.dragsort;
  315. $("#" + preview_id).dragsort({
  316. dragSelector: ".move-picture",
  317. dragEnd: function () {
  318. $("#" + preview_id).trigger("fa.preview.change");
  319. },
  320. placeHolderTemplate: '<li class="file-item thumbnail" style="border:1px #009688 dashed;"></li>'
  321. });
  322. });
  323. }
  324. //刷新隐藏textarea的值
  325. var refresh = function (name) {
  326. var data = {};
  327. var textarea = $("textarea[name='" + name + "']");
  328. var container = textarea.prev("ul");
  329. $.each($("input,select,textarea", container).serializeArray(), function (i, j) {
  330. var reg = /\[?(\w+)\]?\[(\w+)\]$/g;
  331. var match = reg.exec(j.name);
  332. if (!match)
  333. return true;
  334. if (!isNaN(match[2])) {
  335. data[i] = j.value;
  336. } else {
  337. match[1] = "x" + parseInt(match[1]);
  338. if (typeof data[match[1]] === 'undefined') {
  339. data[match[1]] = {};
  340. }
  341. data[match[1]][match[2]] = j.value;
  342. }
  343. });
  344. var result = [];
  345. $.each(data, function (i, j) {
  346. result.push(j);
  347. });
  348. textarea.val(JSON.stringify(result));
  349. };
  350. if (preview_id && input_id) {
  351. $(document.body).on("keyup change", "#" + input_id, function (e) {
  352. var inputStr = $("#" + input_id).val();
  353. var inputArr = inputStr.split(/\,/);
  354. var previewObj = $("#" + preview_id);
  355. previewObj.empty();
  356. var tpl = previewObj.data("template") ? previewObj.data("template") : "";
  357. var extend = previewObj.next().is("textarea") ? previewObj.next("textarea").val() : "{}";
  358. var json = {};
  359. try {
  360. json = JSON.parse(extend);
  361. } catch (e) {
  362. }
  363. $.each(inputArr, function (i, j) {
  364. if (!j) {
  365. return true;
  366. }
  367. var suffix = /[\.]?([a-zA-Z0-9]+)$/.exec(j);
  368. suffix = suffix ? suffix[1] : 'file';
  369. //j = Config.upload.fullmode ? Fast.api.cdnurl(j) : j;
  370. var value = (json && typeof json[i] !== 'undefined' ? json[i] : null);
  371. //var data = {url: j, fullurl: Fast.api.cdnurl(j), data: $(that).data(), key: i, index: i, value: value, row: value, suffix: suffix};
  372. var data = {url: j, data: $(that).data(), key: i, index: i, value: value, row: value, suffix: suffix};
  373. laytpl(tpl ? $("#" + tpl).html() : Upload.config.previewtpl).render(data, function(html) {
  374. previewObj.append(html);
  375. });
  376. });
  377. refresh(previewObj.data("name"));
  378. });
  379. $("#" + input_id).trigger("change");
  380. }
  381. if (preview_id) {
  382. //监听文本框改变事件
  383. $("#" + preview_id).on('change keyup', "input,textarea,select", function () {
  384. refresh($(this).closest("ul").data("name"));
  385. });
  386. // 监听事件
  387. $(document.body).on("fa.preview.change", "#" + preview_id, function () {
  388. var urlArr = [];
  389. $("#" + preview_id + " [data-original]").each(function (i, j) {
  390. urlArr.push($(this).data("original"));
  391. });
  392. if (input_id) {
  393. $("#" + input_id).val(urlArr.join(","));
  394. }
  395. refresh($("#" + preview_id).data("name"));
  396. });
  397. // 移除按钮事件
  398. $(document.body).on("click", "#" + preview_id + " .remove-picture", function () {
  399. $(this).closest("li").remove();
  400. $("#" + preview_id).trigger("fa.preview.change");
  401. });
  402. }
  403. if (input_id) {
  404. $("#" + input_id).closest("form").on("reset", function () {
  405. setTimeout($.proxy(function () {
  406. $("#" + input_id, this).trigger("change");
  407. }, this), 0);
  408. });
  409. //粘贴上传、拖拽上传
  410. $("body").on('paste drop', "#" + input_id, function (event) {
  411. var originEvent = event.originalEvent;
  412. var button = $(".plupload[data-input-id='" + $(this).attr("id") + "'],.faupload[data-input-id='" + $(this).attr("id") + "']");
  413. if (event.type === 'paste' && originEvent.clipboardData && originEvent.clipboardData.items) {
  414. var items = originEvent.clipboardData.items;
  415. if ((items.length === 1 && items[0].type.indexOf("text") > -1) || (items.length === 2 && items[1].type.indexOf("text") > -1)) {
  416. } else {
  417. Upload.list[button.attr("id")].paste(originEvent);
  418. return false;
  419. }
  420. }
  421. if (event.type === 'drop' && originEvent.dataTransfer && originEvent.dataTransfer.files) {
  422. Upload.list[button.attr("id")].drop(originEvent);
  423. return false;
  424. }
  425. });
  426. }
  427. });
  428. },
  429. /**
  430. * @deprecated Use upload instead.
  431. */
  432. plupload: function (element, onUploadSuccess, onUploadError, onUploadComplete) {
  433. return Upload.api.upload(element, onUploadSuccess, onUploadError, onUploadComplete);
  434. },
  435. /**
  436. * @deprecated Use upload instead.
  437. */
  438. faupload: function (element, onUploadSuccess, onUploadError, onUploadComplete) {
  439. return Upload.api.upload(element, onUploadSuccess, onUploadError, onUploadComplete);
  440. },
  441. // AJAX异步上传
  442. send: function (file, onUploadSuccess, onUploadError, onUploadComplete) {
  443. var index = layer.msg('上传中', {offset: 't', time: 0});
  444. var id = "dropzone-" + Dropzone.uuidv4();
  445. $('<button type="button" id="' + id + '" class="btn btn-danger hidden faupload" />').appendTo("body");
  446. $("#" + id).data("upload-complete", function (files) {
  447. layer.close(index);
  448. Upload.list[id].removeAllFiles(true);
  449. });
  450. Upload.api.upload("#" + id, onUploadSuccess, onUploadError, onUploadComplete);
  451. setTimeout(function () {
  452. Upload.list[id].addFile(file);
  453. }, 1);
  454. },
  455. custom: {
  456. //自定义上传完成回调
  457. afteruploadcallback: function (response) {
  458. console.log(this, response);
  459. alert("Custom Callback,Response URL:" + response.url);
  460. },
  461. }
  462. }
  463. }
  464. ;
  465. exports('yznUpload',Upload);
  466. });