qiniuUploader.js 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. const CONFIG = require('../config')
  2. const Parse = getApp().Parse
  3. let config = {
  4. qiniuRegion: '',
  5. qiniuImageURLPrefix: '',
  6. qiniuUploadToken: '',
  7. qiniuUploadTokenURL: '',
  8. qiniuUploadTokenFunction: null,
  9. qiniuShouldUseQiniuFileName: false
  10. }
  11. let spaceLimit = 1024 * 1024 * 1024; // 默认1GB
  12. // 在整个程序生命周期中,只需要 init 一次即可
  13. // 如果需要变更参数,再调用 init 即可
  14. function init(options) {
  15. config = {
  16. qiniuRegion: '',
  17. qiniuImageURLPrefix: '',
  18. qiniuUploadToken: '',
  19. qiniuUploadTokenURL: '',
  20. qiniuUploadTokenFunction: null,
  21. qiniuShouldUseQiniuFileName: false
  22. };
  23. updateConfigWithOptions(options);
  24. }
  25. function updateConfigWithOptions(options) {
  26. if (options.region) {
  27. config.qiniuRegion = options.region;
  28. } else {
  29. console.error('qiniu uploader need your bucket region');
  30. }
  31. if (options.uptoken) {
  32. config.qiniuUploadToken = options.uptoken;
  33. } else if (options.uptokenURL) {
  34. config.qiniuUploadTokenURL = options.uptokenURL;
  35. } else if (options.uptokenFunc) {
  36. config.qiniuUploadTokenFunction = options.uptokenFunc;
  37. }
  38. if (options.domain) {
  39. config.qiniuImageURLPrefix = options.domain;
  40. }
  41. config.qiniuShouldUseQiniuFileName = options.shouldUseQiniuFileName
  42. }
  43. function upload(filePath, success, fail, options, progress, cancelTask, before, complete) {
  44. if (null == filePath) {
  45. console.error('qiniu uploader need filePath to upload');
  46. return;
  47. }
  48. options && updateConfigWithOptions(options);
  49. if (config.qiniuUploadToken) {
  50. doUpload(filePath, success, fail, options, progress, cancelTask, before, complete);
  51. } else if (config.qiniuUploadTokenURL) {
  52. getQiniuToken(function () {
  53. doUpload(filePath, success, fail, options, progress, cancelTask, before, complete);
  54. });
  55. } else if (config.qiniuUploadTokenFunction) {
  56. config.qiniuUploadToken = config.qiniuUploadTokenFunction();
  57. if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
  58. console.error('qiniu UploadTokenFunction result is null, please check the return value');
  59. return
  60. }
  61. doUpload(filePath, success, fail, options, progress, cancelTask, before, complete);
  62. } else {
  63. console.error('qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]');
  64. return;
  65. }
  66. }
  67. /* 文件上传函数 */
  68. async function doUpload(filePath, success, fail, options, progress, cancelTask, before, complete) {
  69. if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
  70. console.error('qiniu UploadToken is null, please check the init config or networking');
  71. return
  72. }
  73. let authLoad = await authSpaceCount()
  74. if (!authLoad) {
  75. wx.showModal({
  76. title: '上传失败',
  77. content: '文件存储空间已满,请联系维护人员。',
  78. showCancel: false,
  79. cancelColor: '#000000',
  80. confirmText: '确定',
  81. confirmColor: '#3CC51F',
  82. });
  83. return
  84. }
  85. let url = uploadURLFromRegionCode(config.qiniuRegion);
  86. let fileName = filePath.split('//')[1];
  87. if (options && options.key) {
  88. fileName = options.key;
  89. }
  90. let formData = {
  91. 'token': config.qiniuUploadToken
  92. };
  93. if (!config.qiniuShouldUseQiniuFileName) {
  94. formData['key'] = fileName
  95. }
  96. before && before();
  97. let uploadTask = wx.uploadFile({
  98. url: url,
  99. filePath: filePath,
  100. name: 'file',
  101. formData: formData,
  102. success: async function (res) {
  103. let dataString = res.data
  104. try {
  105. let dataObject = JSON.parse(dataString);
  106. //do something
  107. let fileUrl = config.qiniuImageURLPrefix + '/' + dataObject.key;
  108. dataObject.fileUrl = fileUrl
  109. dataObject.imageURL = fileUrl;
  110. let size = await getFileInfo(filePath)
  111. dataObject.size = size
  112. console.log(dataObject);
  113. if (success) {
  114. success(dataObject);
  115. }
  116. let type = dataObject.imageURL.split('.').slice(-1)
  117. let startIndex = dataObject.imageURL.lastIndexOf('/')
  118. let name = dataObject.imageURL.slice(startIndex + 1)
  119. let file = {
  120. name: name,
  121. type: formatFile(type),
  122. size: size,
  123. url: dataObject.fileUrl,
  124. }
  125. console.log(file);
  126. saveAttachment(file)
  127. } catch (e) {
  128. console.log('parse JSON failed, origin String is: ' + dataString)
  129. if (fail) {
  130. fail(e);
  131. }
  132. }
  133. },
  134. fail: function (error) {
  135. console.error(error);
  136. if (fail) {
  137. fail(error);
  138. }
  139. },
  140. complete: function (data) {
  141. complete && complete(data);
  142. }
  143. })
  144. uploadTask.onProgressUpdate((res) => {
  145. progress && progress(res)
  146. })
  147. cancelTask && cancelTask(() => {
  148. uploadTask.abort()
  149. })
  150. }
  151. function getQiniuToken(callback) {
  152. wx.request({
  153. url: config.qiniuUploadTokenURL,
  154. success: function (res) {
  155. let token = res.data.uptoken;
  156. if (token && token.length > 0) {
  157. config.qiniuUploadToken = token;
  158. if (callback) {
  159. callback();
  160. }
  161. } else {
  162. console.error('qiniuUploader cannot get your token, please check the uptokenURL or server')
  163. }
  164. },
  165. fail: function (error) {
  166. console.error('qiniu UploadToken is null, please check the init config or networking: ' + error);
  167. }
  168. })
  169. }
  170. function uploadURLFromRegionCode(code) {
  171. let uploadURL = null;
  172. switch (code) {
  173. case 'ECN': uploadURL = 'https://up.qiniup.com'; break;
  174. case 'NCN': uploadURL = 'https://up-z1.qiniup.com'; break;
  175. case 'SCN': uploadURL = 'https://up-z2.qiniup.com'; break;
  176. case 'NA': uploadURL = 'https://up-na0.qiniup.com'; break;
  177. case 'ASG': uploadURL = 'https://up-as0.qiniup.com'; break;
  178. default: console.error('please make the region is with one of [ECN, SCN, NCN, NA, ASG]');
  179. }
  180. return uploadURL;
  181. }
  182. /* 上传校验空间 */
  183. async function authSpaceCount() {
  184. let company = CONFIG.default.company
  185. let query = new Parse.Query("Company");
  186. query.select("configSpace")
  187. let comObj = await query.get(company);
  188. let limit = comObj.get("configSpace") && comObj.get("configSpace").limit;
  189. return new Promise((res, rej) => {
  190. wx.request({
  191. url: `https://server.fmode.cn/api/storage/space?c=${company}`,
  192. data: {},
  193. header: { 'content-type': 'application/json' },
  194. method: 'GET',
  195. dataType: 'json',
  196. responseType: 'text',
  197. success: (result) => {
  198. let data = result?.data?.data
  199. let spaceMap = data;
  200. let _spaceLimit = getLimitBytes(limit) || spaceLimit;
  201. let spaceUsed = spaceMap.totalSize;
  202. console.log('总空间:', _spaceLimit);
  203. console.log('已用空间:', spaceUsed);
  204. if (!_spaceLimit || spaceUsed > _spaceLimit) {
  205. res(false)
  206. return
  207. }
  208. res(true)
  209. },
  210. fail: (err) => {
  211. console.warn(err);
  212. rej('request space API fail')
  213. },
  214. complete: () => { }
  215. });
  216. })
  217. }
  218. // 单位
  219. function getLimitBytes(limit) {
  220. if (limit) {
  221. let num = Number(limit.slice(0, limit.length - 2))
  222. let unit = limit.slice(-2)
  223. switch (unit) {
  224. case "EB":
  225. unit = 1024 * 1024 * 1024 * 1024 * 1024 * 1024
  226. break;
  227. case "PB":
  228. unit = 1024 * 1024 * 1024 * 1024 * 1024
  229. break;
  230. case "TB":
  231. unit = 1024 * 1024 * 1024 * 1024
  232. break;
  233. case "GB":
  234. unit = 1024 * 1024 * 1024
  235. break;
  236. case "MB":
  237. unit = 1024 * 1024
  238. break;
  239. case "KB":
  240. unit = 1024
  241. break;
  242. default:
  243. break;
  244. }
  245. return num * unit
  246. }
  247. return 0
  248. }
  249. //上传保存Attachment
  250. async function saveAttachment(file, cateId) {
  251. let query = new Parse.Query("Attachment");
  252. query.equalTo("url", file.url);
  253. let attachment = await query.first();
  254. if (attachment && attachment.id) {
  255. console.error("该文件已存在,无需重复上传");
  256. return
  257. } else {
  258. let Attachment = Parse.Object.extend("Attachment")
  259. attachment = new Attachment();
  260. attachment.set("size", file.size)
  261. attachment.set("url", file.url)
  262. attachment.set("name", file.name)
  263. attachment.set("mime", file.type)
  264. attachment.set("company", {
  265. __type: "Pointer",
  266. className: "Company",
  267. objectId: CONFIG.default.company
  268. })
  269. cateId && attachment.set("category", {
  270. __type: "Pointer",
  271. className: "Category",
  272. objectId: cateId
  273. })
  274. return await attachment.save()
  275. }
  276. }
  277. // 获取本地存储文件大小
  278. function getFileInfo(filePath) {
  279. return new Promise((result) => {
  280. wx.getFileInfo({
  281. filePath: filePath,
  282. success(res) {
  283. result(res.size)
  284. },
  285. fail(err){
  286. result(0)
  287. }
  288. })
  289. })
  290. }
  291. function formatFile(type) {
  292. let fileJson = {
  293. "doc": "xapplication/vnd.openxmlformats-officedocument.wordprocessingml.document",
  294. "doc": "application/msword",
  295. "pdf": "application/pdf",
  296. "rtf": "application/rtf",
  297. "xls": "application/vnd.ms-excel",
  298. "ppt": "application/vnd.ms-powerpoint",
  299. "rar": "application/x-rar-compressed",
  300. "swf": "application/x-shockwave-flash",
  301. "zip": "application/zip",
  302. "mid": "audio/midi",
  303. "midi": "audio/midi",
  304. "kar": "audio/midi",
  305. "mp3": "audio/mpeg",
  306. "ogg": "audio/ogg",
  307. "m4a": "audio/x-m4a",
  308. "ra": "audio/x-realaudio",
  309. "gif": "image/gif",
  310. "jpeg": "image/jpeg",
  311. "jpg": "image/jpeg",
  312. "png": "image/png",
  313. "tif": "image/tiff",
  314. "tiff": " image/tiff",
  315. "wbmp": " image/vnd.wap.wbmp",
  316. "ico": "image/x-icon",
  317. "jng": "image/x-jng",
  318. "bmp": "image/x-ms-bmp",
  319. "svg": "image/svg+xml",
  320. "svgz": " image/svg+xml",
  321. "webp": " image/webp",
  322. "css": "text/css",
  323. "html": " text/html",
  324. "htm": "text/html",
  325. "shtm": "l text/html",
  326. "txt": "text/plain",
  327. "xml": "text/xml",
  328. "3gpp": " video/3gpp",
  329. "3gp": "video/3gpp",
  330. "mp4": "video/mp4",
  331. "mpeg": " video/mpeg",
  332. "mpg": "video/mpeg",
  333. "mov": "video/quicktime",
  334. "webm": "video/webm",
  335. "flv": "video/x-flv",
  336. "m4v": "video/x-m4v",
  337. "wmv": "video/x-ms-wmv",
  338. "avi": "video/x-msvideo",
  339. }
  340. return fileJson[type] || type
  341. }
  342. module.exports = {
  343. init: init,
  344. upload: upload,
  345. }