uploadFile.html 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <!DOCTYPE html>
  2. <html lang="zh-cn">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title class="title">[文件管理器]</title>
  6. <meta name="viewport"
  7. content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
  8. <style type="text/css">
  9. .content {
  10. background: transparent;
  11. }
  12. .btn {
  13. position: relative;
  14. top: 0;
  15. left: 0;
  16. bottom: 0;
  17. right: 0;
  18. }
  19. .btn .file {
  20. position: fixed;
  21. z-index: 93;
  22. left: 0;
  23. right: 0;
  24. top: 0;
  25. bottom: 0;
  26. width: 100%;
  27. opacity: 0;
  28. }
  29. </style>
  30. </head>
  31. <body>
  32. <div id="content" class="content">
  33. <div class="btn">
  34. <input :multiple="multiple" @change="onChange" :accept="accept" ref="file" class="file" type="file" />
  35. </div>
  36. </div>
  37. <script type="text/javascript" src="js/vue.min.js"></script>
  38. <script type="text/javascript">
  39. let _this;
  40. var vm = new Vue({
  41. el: '#content',
  42. data: {
  43. accept: '',
  44. multiple: true,
  45. },
  46. mounted() {
  47. console.log('加载webview');
  48. _this = this;
  49. this.files = new Map();
  50. document.addEventListener('plusready', (e) => {
  51. let {
  52. debug,
  53. instantly,
  54. prohibited
  55. } = plus.webview.currentWebview();
  56. this.debug = debug;
  57. this.instantly = instantly;
  58. this.prohibited = prohibited;
  59. this.accept = prohibited.accept;
  60. if (prohibited.multiple === 'false') {
  61. prohibited.multiple = false;
  62. }
  63. this.multiple = prohibited.multiple;
  64. location.href = 'callback?retype=updateOption';
  65. }, false);
  66. },
  67. methods: {
  68. toast(msg) {
  69. plus.nativeUI.toast(msg);
  70. },
  71. clear(name) {
  72. if (!name) {
  73. this.files.clear();
  74. return;
  75. }
  76. this.files.delete(name);
  77. },
  78. setData(option = '{}') {
  79. this.debug && console.log('更新参数:' + option);
  80. try {
  81. _this.option = JSON.parse(option);
  82. } catch (e) {
  83. console.error('参数设置错误')
  84. }
  85. },
  86. async upload(name = '') {
  87. if (name && this.files.has(name)) {
  88. await this.createUpload(this.files.get(name));
  89. } else {
  90. for (let item of this.files.values()) {
  91. if (item.type === 'waiting' || item.type === 'fail') {
  92. await this.createUpload(item);
  93. }
  94. }
  95. }
  96. },
  97. onChange(e) {
  98. let fileDom = this.$refs.file;
  99. for (let file of fileDom.files) {
  100. if (this.files.size >= this.prohibited.count) {
  101. this.toast(`只允许上传${this.prohibited.count}个文件`);
  102. fileDom.value = '';
  103. break;
  104. }
  105. this.addFile(file);
  106. }
  107. this.uploadAfter();
  108. fileDom.value = '';
  109. },
  110. addFile(file) {
  111. if (file) {
  112. const units = {
  113. KB: 1024,
  114. MB: 1024 * 1024,
  115. GB: 1024 * 1024 * 1024,
  116. };
  117. let name = file.name;
  118. this.debug && console.log('文件名称', name, '大小', file.size);
  119. // 限制文件格式
  120. let suffix = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
  121. let formats = this.prohibited.formats.toLowerCase();
  122. if (formats && !formats.includes(suffix)) {
  123. this.toast(`不支持上传${suffix.toUpperCase()}格式文件`);
  124. return;
  125. }
  126. // 限制文件大小
  127. if (file.size > units[this.prohibited.sizeUnit] * Math.abs(this.prohibited.size)) {
  128. this.toast(`文件大小超过${this.prohibited.size}${this.prohibited.sizeUnit}`)
  129. return;
  130. }
  131. // let itemBlob = new Blob([file]);
  132. let path = URL.createObjectURL(file);
  133. this.files.set(file.name, {
  134. file,
  135. path,
  136. fullName: file.name,
  137. name: file.name,
  138. size: file.size,
  139. progress: 0,
  140. type: 'waiting'
  141. });
  142. }
  143. },
  144. /**
  145. * @returns {Map} 已选择的文件Map集
  146. */
  147. callChange() {
  148. location.href = 'callback?retype=change&files=' + escape(JSON.stringify([...this.files]));
  149. },
  150. /**
  151. * @returns {object} 正在处理的当前对象
  152. */
  153. changeFilesItem(item, end = '') {
  154. this.files.set(item.name, item);
  155. location.href = 'callback?retype=progress&end=' + end + '&item=' + escape(JSON.stringify(item));
  156. },
  157. uploadAfter() {
  158. this.callChange();
  159. setTimeout(() => {
  160. this.instantly && this.upload();
  161. }, 1000)
  162. },
  163. createUpload(item) {
  164. this.debug && console.log('准备上传,option=:' + JSON.stringify(this.option));
  165. item.type = 'loading';
  166. delete item.responseText;
  167. return new Promise((resolve, reject) => {
  168. let {
  169. url,
  170. name,
  171. method = 'POST',
  172. header = {},
  173. formData = {},
  174. data = {},
  175. parentId
  176. } = this.option;
  177. let form = new FormData();
  178. for (let keys in formData) {
  179. form.append(keys, formData[keys])
  180. }
  181. for (let keys in data) {
  182. form.append(keys, data[keys])
  183. }
  184. form.append(name, item.file);
  185. let xmlRequest = new XMLHttpRequest();
  186. xmlRequest.open(method, `${url}?parentId=${parentId}`, true);
  187. for (let keys in header) {
  188. xmlRequest.setRequestHeader(keys, header[keys])
  189. }
  190. xmlRequest.upload.addEventListener(
  191. 'progress',
  192. event => {
  193. if (event.lengthComputable) {
  194. let progress = Math.ceil((event.loaded * 100) / event.total)
  195. if (progress <= 100) {
  196. item.progress = progress;
  197. this.changeFilesItem(item);
  198. }
  199. }
  200. },
  201. false
  202. );
  203. xmlRequest.ontimeout = () => {
  204. console.error('请求超时')
  205. item.type = 'fail';
  206. this.changeFilesItem(item, true);
  207. return resolve(false);
  208. }
  209. xmlRequest.onreadystatechange = ev => {
  210. if (xmlRequest.readyState == 4) {
  211. this.debug && console.log('接口是否支持跨域', xmlRequest.withCredentials);
  212. if (xmlRequest.status == 200) {
  213. this.debug && console.log('上传完成:' + xmlRequest.responseText)
  214. item['responseText'] = xmlRequest.responseText;
  215. item.type = 'success';
  216. this.changeFilesItem(item, true);
  217. return resolve(true);
  218. } else if (xmlRequest.status == 0) {
  219. console.error(
  220. 'status = 0 :请检查请求头Content-Type与服务端是否匹配,服务端已正确开启跨域,并且nginx未拦截阻止请求'
  221. )
  222. }
  223. console.error('--ERROR--:status = ' + xmlRequest.status)
  224. item.type = 'fail';
  225. this.changeFilesItem(item, true);
  226. return resolve(false);
  227. }
  228. }
  229. xmlRequest.send(form)
  230. });
  231. }
  232. }
  233. });
  234. </script>
  235. </body>
  236. </html>