file.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /**
  2. * 文件相关操作
  3. * 文件选择、上传、获取文件类型图标、文件下载
  4. */
  5. import { BASE_URL_FN, STATIC_URL_FN } from '../config.js'
  6. // #ifdef APP-PLUS
  7. const sys = uni.getSystemInfoSync()
  8. let uploadPlugin = null
  9. if (sys.platform === 'android') {
  10. uploadPlugin = uni.requireNativePlugin('FileUpload')
  11. }
  12. // #endif
  13. /**
  14. * 文件选择、生成 formData 数据上传
  15. */
  16. export default class WkFile {
  17. constructor(params = {}) {
  18. if (['img', 'file'].includes(params.type)) {
  19. this.type = params.type
  20. } else {
  21. this.type = 'file'
  22. }
  23. this.fileList = []
  24. this.filePathList = []
  25. this.autoUpload = params.hasOwnProperty('autoUpload') ? params.autoUpload : true
  26. this.isAndroid = false
  27. // #ifdef APP-PLUS
  28. this.isAndroid = uni.getSystemInfoSync().platform === 'android'
  29. // #endif
  30. if (params.batchId) this.batchId = params.batchId
  31. }
  32. /**
  33. * 选择文件
  34. */
  35. choose() {
  36. const that = this
  37. return new Promise((resolve, reject) => {
  38. const chooseImage = () => {
  39. // 选择图片文件
  40. uni.chooseImage({
  41. count: 1,
  42. sizeType: ['original'],
  43. success: data => {
  44. console.log('choose data: ', data)
  45. that.fileList = data.tempFiles
  46. that.filePathList = data.tempFilePaths
  47. if (!that.autoUpload) {
  48. resolve(data)
  49. } else {
  50. that.uploadAll().then(res => {
  51. resolve(res)
  52. }).catch((error) => {
  53. console.log('choose uploadAll error:', error)
  54. reject(error)
  55. })
  56. }
  57. },
  58. fail: (error) => {
  59. reject(error)
  60. }
  61. })
  62. }
  63. if (this.type === 'img') {
  64. chooseImage()
  65. } else {
  66. // 选择附件
  67. // #ifdef H5
  68. const oldEl = document.getElementById('fileHook')
  69. if (oldEl) {
  70. oldEl.parentNode.removeChild(oldEl)
  71. }
  72. const el = document.createElement('input')
  73. el.type = 'file'
  74. el.id = 'fileHook'
  75. el.style.display = 'none'
  76. el.onchange = evt => {
  77. console.log(evt.target.files)
  78. that.fileList = evt.target.files
  79. that.uploadAll().then(res => {
  80. resolve(res)
  81. }).catch((error) => {
  82. console.log('choose uploadAll error:', error)
  83. reject()
  84. })
  85. }
  86. document.body.appendChild(el)
  87. el.click()
  88. // #endif
  89. // #ifdef APP-PLUS
  90. const sys = uni.getSystemInfoSync()
  91. if (that.isAndroid && uploadPlugin) {
  92. // Android
  93. that.androidChooseFile(path => {
  94. console.log('path: ', path)
  95. that.filePathList = [path]
  96. if (!that.autoUpload) {
  97. resolve(that.filePathList)
  98. } else {
  99. that.uploadAll().then(res => {
  100. resolve(res)
  101. }).catch((error) => {
  102. console.log('choose uploadAll error:', error)
  103. reject()
  104. })
  105. }
  106. })
  107. } else {
  108. // IOS 暂时不支持选择附件,使用选择图片代替
  109. chooseImage()
  110. }
  111. // #endif
  112. // #ifndef APP-PLUS || H5
  113. chooseImage()
  114. // #endif
  115. }
  116. })
  117. }
  118. /**
  119. * android 选择附件
  120. */
  121. androidChooseFile(callbackFunc) {
  122. uploadPlugin.chooseFile(
  123. {},
  124. data => {
  125. callbackFunc(data.path)
  126. }
  127. )
  128. }
  129. /**
  130. * 上传单个文件
  131. * @param {String} filePath 文件路径
  132. */
  133. androidUploadOne(filePath) {
  134. // if (filePath.startsWith('file://')) {
  135. // filePath = filePath.replace('file://', '')
  136. // }
  137. // if (!filePath.startsWith('/')) {
  138. // filePath = '/' + filePath
  139. // }
  140. return new Promise((resolve, reject) => {
  141. const formData = {
  142. type: this.type
  143. }
  144. if (this.batchId) {
  145. formData.batchId = this.batchId
  146. }
  147. const header = {
  148. 'Admin-Token': uni.getStorageSync('token') || ''
  149. }
  150. const appid = uni.getStorageSync('appid') || ''
  151. if (appid) {
  152. header.k = appid
  153. }
  154. uploadPlugin.upload(
  155. {
  156. url: BASE_URL_FN() + 'adminFile/upload',
  157. name: 'file',
  158. filePath: filePath,
  159. header,
  160. formData: formData,
  161. timeout: 5 * 60
  162. }, res => {
  163. console.log('uplload res: ', res)
  164. resolve(res.data)
  165. }, (err) => {
  166. console.log('plugin upload error', err)
  167. reject('上传失败')
  168. }
  169. )
  170. })
  171. }
  172. /**
  173. * 上传单个文件
  174. * @param {String} filePath 文件路径
  175. */
  176. uploadOne(data) {
  177. return new Promise((resolve, reject) => {
  178. const formData = {
  179. type: this.type
  180. }
  181. if (this.batchId) {
  182. formData.batchId = this.batchId
  183. }
  184. const header = {
  185. 'Admin-Token': uni.getStorageSync('token') || ''
  186. }
  187. const appid = uni.getStorageSync('appid') || ''
  188. if (appid) {
  189. header.k = appid
  190. }
  191. const requestConfig = {
  192. url: BASE_URL_FN() + 'adminFile/upload',
  193. fileType: 'image',
  194. name: 'file',
  195. header,
  196. formData: formData,
  197. success: res => {
  198. let data = res.data
  199. if (typeof res.data === 'string') {
  200. try {
  201. data = JSON.parse(res.data)
  202. } catch (e) {
  203. console.log('parse error: ', e)
  204. }
  205. }
  206. resolve(data.data || data)
  207. },
  208. fail: (error) => {
  209. console.log('err', error)
  210. reject('上传失败')
  211. }
  212. }
  213. // #ifdef H5
  214. if (typeof data === 'string') {
  215. requestConfig.filePath = data
  216. } else {
  217. requestConfig.file = data
  218. }
  219. // #endif
  220. // #ifndef H5
  221. requestConfig.filePath = data
  222. // #endif
  223. console.log('upload config: ', requestConfig)
  224. uni.uploadFile(requestConfig)
  225. })
  226. }
  227. /**
  228. * 批量上传文件
  229. */
  230. uploadAll() {
  231. return new Promise((resolve, reject) => {
  232. const that = this
  233. const arr = []
  234. // #ifdef H5
  235. if (this.type !== 'img') {
  236. this.fileList.forEach(file => {
  237. arr.push(that.uploadOne(file))
  238. })
  239. } else {
  240. this.filePathList.forEach(filePath => {
  241. arr.push(that.uploadOne(filePath))
  242. })
  243. }
  244. // #endif
  245. // #ifndef H5
  246. if (this.isAndroid && uploadPlugin && this.type === 'file') {
  247. this.filePathList.forEach(filePath => {
  248. arr.push(that.androidUploadOne(filePath))
  249. })
  250. } else {
  251. this.filePathList.forEach(filePath => {
  252. arr.push(that.uploadOne(filePath))
  253. })
  254. }
  255. // #endif
  256. uni.showLoading({
  257. mask: true,
  258. title: '加载中'
  259. })
  260. Promise.all(arr).then(res => {
  261. console.log('uploadAll res', res)
  262. uni.hideLoading()
  263. resolve(res)
  264. }).catch((error) => {
  265. console.log('uploadAll err', error)
  266. uni.hideLoading()
  267. reject('批量上传失败')
  268. })
  269. })
  270. }
  271. }
  272. const $static = STATIC_URL_FN
  273. /**
  274. * 根据文件 url 获取文件相应类型的icon
  275. * @param url
  276. * @returns {*}
  277. */
  278. export function calcIcon(url) {
  279. let temps = url ? url.split('.') : []
  280. let ext = ''
  281. if (temps.length > 0) {
  282. ext = temps[temps.length - 1].toLowerCase()
  283. } else {
  284. ext = ''
  285. }
  286. // console.log('file type: ', ext)
  287. const typeMap = {
  288. img: {
  289. types: ['bmp', 'jpg', 'png', 'jpeg', 'gif', 'svg', 'webp'],
  290. icon: $static('images/file/file_img.png')
  291. },
  292. excel: {
  293. types: ['xls', 'xlsx'],
  294. icon: $static('images/file/file_excel.png')
  295. },
  296. ppt: {
  297. types: ['ppt', 'pptx'],
  298. icon: $static('images/file/file_ppt.png')
  299. },
  300. word: {
  301. types: ['doc', 'docx'],
  302. icon: $static('images/file/file_word.png')
  303. },
  304. pdf: {
  305. types: ['pdf'],
  306. icon: $static('images/file/file_pdf.png')
  307. },
  308. txt: {
  309. types: ['txt', 'text'],
  310. icon: $static('images/file/file_txt.png')
  311. },
  312. video: {
  313. types: ['mp4', 'mp3', 'avi', 'wmv', 'flv', 'rmvb'],
  314. icon: $static('images/file/file_video.png')
  315. },
  316. zip: {
  317. types: ['rar', 'zip', '7z'],
  318. icon: $static('images/file/file_zip.png')
  319. },
  320. }
  321. let res = Object.keys(typeMap).find(key => {
  322. return typeMap[key].types.includes(ext)
  323. })
  324. if (res) return typeMap[res].icon
  325. return $static('images/file/file_unknown.png')
  326. }
  327. /**
  328. * 文件下载
  329. * @param {Object} file
  330. * @param {String} file.url 文件 url 地址
  331. * @param {String} file.name 文件名 eg: 1.txt
  332. */
  333. export function downloadFile(file) {
  334. if (!file || !file.url) {
  335. uni.showToast({
  336. title: '文件下载失败'
  337. })
  338. return
  339. }
  340. let url = BASE_URL_FN() + (file.url.startsWith('/') ? file.url.replace('/', '') : file.url)
  341. let temps = file.name ? file.name.split('.') : []
  342. let ext = ''
  343. if (temps.length > 0) {
  344. ext = temps[temps.length - 1].toLowerCase()
  345. } else {
  346. ext = ''
  347. }
  348. const token = uni.getStorageSync('token') || ''
  349. const appid = uni.getStorageSync('appid') || ''
  350. if ([
  351. 'bmp',
  352. 'jpg',
  353. 'png',
  354. 'jpeg',
  355. 'gif',
  356. 'svg',
  357. 'webp'
  358. ].includes(ext)) {
  359. url = url + '?c=' + token
  360. if (appid) {
  361. url = url + '&k=' + appid
  362. }
  363. uni.previewImage({
  364. urls: [url],
  365. indicator: 'number'
  366. })
  367. return
  368. }
  369. uni.showLoading({
  370. title: '正在加载..',
  371. mask: true
  372. })
  373. const header = {
  374. 'Admin-Token': token
  375. }
  376. if (appid) {
  377. header.k = appid
  378. }
  379. uni.downloadFile({
  380. url,
  381. header,
  382. success: res => {
  383. uni.hideLoading()
  384. // #ifdef H5
  385. const el = document.createElement('a')
  386. el.href = res.tempFilePath
  387. el.download = file.name
  388. el.style.display = 'none'
  389. document.body.appendChild(el)
  390. el.click()
  391. el.parentNode.removeChild(el)
  392. // #endif
  393. // #ifndef H5
  394. if ([
  395. 'doc',
  396. 'xls',
  397. 'ppt',
  398. 'pdf',
  399. 'docx',
  400. 'xlsx',
  401. 'pptx'
  402. ].includes(ext)) {
  403. const sys = uni.getSystemInfoSync()
  404. let tempFilePath = res.tempFilePath
  405. if (sys.platform === 'ios') {
  406. tempFilePath = escape(tempFilePath)
  407. }
  408. uni.saveFile({
  409. tempFilePath,
  410. success: res => {
  411. console.log('save success: ', res)
  412. uni.showToast({
  413. title: '文件已保存至' + res.savedFilePath
  414. })
  415. uni.openDocument({
  416. filePath: res.savedFilePath,
  417. fileType: ext
  418. })
  419. },
  420. fail: error => {
  421. console.log('save error: ', error)
  422. uni.showToast({
  423. title: '文件保存失败',
  424. icon: 'none'
  425. })
  426. }
  427. })
  428. } else {
  429. // #ifdef APP-PLUS
  430. plus.runtime.openFile(res.tempFilePath)
  431. // #endif
  432. // #ifdef MP-WEIXIN
  433. uni.showToast({
  434. title: '该文件暂不支持预览'
  435. })
  436. // #endif
  437. // #ifndef APP-PLUS | MP-WEIXIN
  438. uni.saveFile({
  439. tempFilePath: res.tempFilePath,
  440. success: res => {
  441. console.log('save:', res)
  442. uni.showToast({
  443. title: '文件已保存至' + res.savedFilePath
  444. })
  445. },
  446. fail: () => {
  447. uni.showToast({
  448. title: '文件保存失败',
  449. icon: 'none'
  450. })
  451. }
  452. })
  453. // #endif
  454. }
  455. // #endif
  456. },
  457. fail: () => {
  458. uni.hideLoading()
  459. uni.showToast({
  460. title: '文件下载失败',
  461. icon: 'none'
  462. })
  463. }
  464. })
  465. }