upload.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. import guid from './guid';
  2. /**
  3. * 上传文件。
  4. * 作者:tmzdy
  5. * 时间:‎2021‎年‎7‎月‎28‎日,‏‎9:14:53
  6. * 联系:zhongjihan@sina.com
  7. * @param {Function} chooesefile -- 选择图片上传
  8. * @param {Function} selected -- 选择图片成功后触发。返回选择后的图片。
  9. * @param {Function} addfile -- 动态加入预上传的文件。
  10. * @param {Function} progress -- 进度。
  11. * @param {Function} fail -- 失败。
  12. * @param {Function} success -- 成功。
  13. * @param {Function} complete -- 完成。
  14. * @param {Function} start -- 开始上传。
  15. * @param {Function} stop -- 停止上传。
  16. */
  17. class uploadfile {
  18. filelist = [];
  19. isStop = false;
  20. index = 0;
  21. constructor({maxfile,uploadUrl,opts,responseStu,file_list,isAuto}) {
  22. let arg = {
  23. maxfile:9,
  24. uploadUrl:'',
  25. file_list:[],
  26. isAuto:true,
  27. opts:{},
  28. maxsize:10*1024*1024,
  29. code:0,//定义成功的标志码
  30. type:'image',//文件选择的类型
  31. extension:['*'],//后缀过滤。
  32. responseStu:{
  33. code:'code',//服务器返回的码的字段名称
  34. data:'data',//服务上传成功后返回 的数据字段名称
  35. msg:'msg'//服务器响应信息的字段名称。
  36. },
  37. ...(arguments[0]??{})};
  38. let ots = {
  39. name:'file',header:{}
  40. }//配置{name: 'file', // 上传时的文件key名。默认file,header: {}, // 上传的头部参数。}
  41. this.config={
  42. maxfile:arg.maxfile,
  43. uploadUrl:arg.uploadUrl,
  44. opts:{...ots,...arg.opts},
  45. file_list:arg.file_list,//默认提供的图片.
  46. maxsize:arg.maxsize,
  47. code:arg.code,
  48. isAuto:arg.isAuto,//自动上传
  49. type:arg.type,//文件选择的类型
  50. extension:arg.extension,//后缀过滤。
  51. responseStu:{...arg.responseStu,...(responseStu||{})}
  52. }
  53. }
  54. /**
  55. * 成功后返回选择后的图片列表。
  56. */
  57. async chooesefile(){
  58. let t = this;
  59. return new Promise((rs,rj)=>{
  60. uni.chooseImage({
  61. count:t.config.maxfile,
  62. type:t.config.type,
  63. extension:t.config.extension,
  64. fail: (e) => {
  65. console.error(e);
  66. uni.$tm.toast("已取消选择");
  67. rj(e);
  68. },
  69. success: (res) => {
  70. console.log(res);
  71. if(res.tempFilePaths.length==0){
  72. uni.$tm.toast("未选择");
  73. return;
  74. }
  75. console.log(res);
  76. let imgarray = res.tempFilePaths;
  77. let fielist = res.tempFiles;
  78. let jgsk = [];
  79. //0待上传,1上传中,2上传失败,3上传成功。4超过大小限制
  80. imgarray.forEach((item,index)=>{
  81. let isMaxsize = fielist[index].size>t.config.maxsize?true:false;
  82. jgsk.push({
  83. url:item,
  84. status:isMaxsize?'超过大小':"待上传",
  85. progress:isMaxsize?100:0,
  86. fileId:guid(),
  87. statusCode:isMaxsize?4:0,
  88. data:null,//上传成功后的回调数据。
  89. })
  90. })
  91. t.filelist.push(...jgsk)
  92. t.selected(t.filelist);
  93. if(t.config.isAuto){
  94. t.start();
  95. }
  96. rs(t.filelist)
  97. }
  98. })
  99. })
  100. }
  101. async chooseMPH5weixinFile(){
  102. let t = this;
  103. return new Promise((rs,rj)=>{
  104. var fs = uni.chooseFile;
  105. // #ifdef MP-WEIXIN || MP-QQ
  106. fs = uni.chooseMessageFile;
  107. // #endif
  108. var config = {
  109. count:t.config.maxfile,
  110. type:t.config.type,
  111. extension:t.config.extension,
  112. }
  113. if(!t.config.extension||!Array.isArray(t.config.extension)||t.config.extension?.length==0){
  114. delete config.extension
  115. }
  116. fs({
  117. ...config,
  118. fail: (e) => {
  119. console.error(e);
  120. uni.$tm.toast("已取消选择");
  121. rj(e);
  122. },
  123. success: (res) => {
  124. if(res.tempFiles.length==0){
  125. uni.$tm.toast("未选择");
  126. return;
  127. }
  128. let fielist = res.tempFiles;
  129. let jgsk = [];
  130. //0待上传,1上传中,2上传失败,3上传成功。4超过大小限制
  131. fielist.forEach((item,index)=>{
  132. let isMaxsize = fielist[index].size>t.config.maxsize?true:false;
  133. let ftype = item.name||""
  134. if(ftype){
  135. ftype = ftype.substr(ftype.lastIndexOf(".")+1).toLocaleLowerCase();
  136. }
  137. jgsk.push({
  138. url:item.path,
  139. name:item.name||'默认文件名称',
  140. type:ftype,
  141. status:isMaxsize?'超过大小':"待上传",
  142. progress:isMaxsize?100:0,
  143. fileId:guid(),
  144. statusCode:isMaxsize?4:0,
  145. data:null,//上传成功后的回调数据。
  146. })
  147. })
  148. t.filelist.push(...jgsk)
  149. t.selected(t.filelist);
  150. if(t.config.isAuto){
  151. t.start();
  152. }
  153. rs(t.filelist)
  154. }
  155. })
  156. })
  157. }
  158. setConfig({maxfile,uploadUrl,opts,file_list,isAuto,responseStu}){
  159. let arg = arguments.length==0?{}:arguments[0];
  160. this.config={...this.config,...arg}
  161. }
  162. // 动态加入预上传的文件。
  163. /**
  164. * 动态加入文件
  165. * @param {Object} filelist
  166. */
  167. addfile(filelist){
  168. if(typeof filelist !=='object'&&!Array.isArray(filelist)) return;
  169. this.filelist.push(...filelist)
  170. }
  171. // 选择图片成功后触发。返回选择后的图片。
  172. selected(filelist){}
  173. // 进度。
  174. progress(item){}
  175. // 失败
  176. fail(item){}
  177. // 成功
  178. success(item){}
  179. // 完成。
  180. complete (filelist){}
  181. // 开始上传。
  182. start(){
  183. if(this.filelist.length<=0){
  184. uni.$tm.toast("未选择图片");
  185. return;
  186. }
  187. let t = this;
  188. // t重新开始上传从头开始。
  189. this.index = 0;
  190. this.isStop = false;
  191. function startupload(){
  192. if(t.isStop) return;
  193. let item = t.filelist[t.index];
  194. if(!item || typeof item === 'undefined'){
  195. // 文件不存在。直接结束。
  196. t.complete(t.filelist);
  197. return;
  198. }
  199. if(item.statusCode==3||item.statusCode==1||item.statusCode==4){
  200. // 直接跳过。至下一个文件。
  201. t.index++;
  202. startupload();
  203. return;
  204. }
  205. const upObj = uni.uploadFile({
  206. url:t.config.uploadUrl,
  207. name:t.config.opts?.name??'file',
  208. header:t.config.opts?.header??{},
  209. filePath:item.url,
  210. formData:{file_name:item.name},
  211. success:(res)=>{
  212. if(res.statusCode !=200){
  213. item.statusCode = 2;
  214. item.status = "上传失败";
  215. uni.$tm.toast(String(res.statusCode))
  216. t.fail(item)
  217. t.index++;
  218. return;
  219. }
  220. let jsd={};
  221. let isOk = true;
  222. // 是否从服务器返回的是json。如果不是则表示fasle为string.
  223. let isJsonCallbackData = true;
  224. try{
  225. jsd = JSON.parse(res.data);
  226. }catch(e){
  227. isJsonCallbackData=false;
  228. jsd = res.data;
  229. item.data = res.data;
  230. }
  231. if(isJsonCallbackData){
  232. try{
  233. item.data = jsd[t.config.responseStu.data];
  234. if(typeof item.data == 'object'){
  235. item.data['name'] = item.name;
  236. item.data['id'] = item['id']||"";
  237. }
  238. let itecode = jsd[t.config.responseStu.code]
  239. if(itecode!==t.config.code){
  240. isOk = false;
  241. }
  242. }catch(e){
  243. isOk = false;
  244. }
  245. }
  246. if(!isOk){
  247. uni.$tm.toast(jsd[t.config.responseStu.msg]||"失败")
  248. item.statusCode = 2;
  249. item.status = "上传失败";
  250. t.fail(item)
  251. t.index++;
  252. return;
  253. }
  254. // 上传成功。
  255. item.statusCode = 3;
  256. item.status = "上传成功";
  257. uni.$tm.toast("上传成功")
  258. // t.filelist[t.index] = item;
  259. // t.filelist.splice(t.index,1,item)
  260. t.success(item)
  261. },
  262. fail:(res)=>{
  263. uni.$tm.toast(res.errMsg)
  264. item.statusCode = 2;
  265. item.status = "上传失败";
  266. // t.filelist[t.index] = item;
  267. t.fail(item)
  268. t.index++;
  269. },
  270. complete:(res)=>{
  271. // 直接下一个文件。
  272. startupload();
  273. }
  274. })
  275. if(upObj){
  276. upObj.onProgressUpdate((res)=>{
  277. t.filelist[t.index].statusCode = 1;
  278. t.filelist[t.index].status = "上传中";
  279. t.filelist[t.index].progress = res.progress;
  280. // t.filelist[t.index] = item;
  281. t.progress(item)
  282. })
  283. }
  284. }
  285. startupload();
  286. }
  287. // 停止上传
  288. stop(){
  289. this.isStop = true;
  290. }
  291. }
  292. /**
  293. * 上传文件。
  294. * 作者:tmzdy
  295. * 时间:‎2021‎年‎7‎月‎28‎日,‏‎9:14:53
  296. * 联系:zhongjihan@sina.com
  297. * 选择图片上传,相册或者拍照。
  298. * @param {Number} maxfile 最大上传的文件数量,默认为 9 ;
  299. * @param {String} uploadUrl -- ""
  300. * @param {Object} opts -- {}
  301. * @param {Function} progress {} --上传中调用
  302. * @param {Function} success {} --上传成功才会调用。
  303. * @param {Function} selected {} --选完图片待上传调用。
  304. * @param {Function} fail {} --上传失败时调用,返回文件相关
  305. * @param {Function} complete {} -- 完成上传时触发,失败与成功都触发。
  306. */
  307. function chooseImgUpload(maxfile=9,uploadUrl="",opts={},progress,success,selected,fail,complete){
  308. uni.chooseImage({
  309. count:maxfile,
  310. fail: (e) => {
  311. uni.$tm.toast("用户取消选择图片");
  312. },
  313. success: (res) => {
  314. if(res.tempFilePaths.length==0){
  315. uni.$tm.toast("未选择图片");
  316. return;
  317. }
  318. let imgarray = res.tempFilePaths;
  319. let jgsk = [];
  320. //0待上传,1上传中,2上传失败,3上传成功。
  321. imgarray.forEach((item,index)=>{
  322. jgsk.push({
  323. url:item,
  324. status:"待上传",
  325. progress:0,
  326. fileId:guid(),
  327. statusCode:0,
  328. data:null,//上传成功后的回调数据。
  329. })
  330. })
  331. if(selected){
  332. selected(jgsk);
  333. }
  334. let index = 0;
  335. function startupload(){
  336. let item = jgsk[index];
  337. if(!item){
  338. // 文件不存在。直接结束。
  339. if(complete){
  340. complete(jgsk);
  341. }
  342. return;
  343. }
  344. if(item.statusCode==2||item.statusCode==1){
  345. // 直接跳过。至下一个文件。
  346. index++;
  347. startupload();
  348. }
  349. const upObj = uni.uploadFile({
  350. url:uploadUrl,
  351. name:opts?.name??'file',
  352. header:opts?.header??{},
  353. filePath:item.url,
  354. success:(res)=>{
  355. if(res.statusCode !=200){
  356. item.statusCode = 2;
  357. item.status = "上传失败";
  358. uni.$tm.toast(res.errMsg)
  359. if(fail){
  360. fail(item)
  361. }
  362. return;
  363. }
  364. try{
  365. item.data = JSON.parse(res.data).data;
  366. }catch(e){
  367. item.statusCode = 2;
  368. item.status = "上传失败";
  369. uni.$tm.toast(res.errMsg)
  370. if(fail){
  371. fail(item)
  372. }
  373. return;
  374. }
  375. // 上传成功。
  376. item.statusCode = 3;
  377. item.status = "上传成功";
  378. item.data = JSON.parse(res.data).data;
  379. uni.$tm.toast("上传成功")
  380. if(success){
  381. success(item)
  382. }
  383. },
  384. fail:(res)=>{
  385. uni.$tm.toast(res.errMsg)
  386. item.statusCode = 2;
  387. item.status = "上传失败";
  388. if(fail){
  389. fail(item)
  390. }
  391. },
  392. complete:(res)=>{
  393. // 直接下一个文件。
  394. index++;
  395. startupload();
  396. }
  397. })
  398. if(upObj){
  399. upObj.onProgressUpdate((res)=>{
  400. item.statusCode = 1;
  401. item.status = "上传中";
  402. item.progress = res.progress
  403. if(progress){
  404. progress(item)
  405. }
  406. })
  407. }
  408. }
  409. startupload();
  410. }
  411. })
  412. }
  413. export default {
  414. chooseImgUpload,uploadfile
  415. }