/** * 文件相关操作 * 文件选择、上传、获取文件类型图标、文件下载 */ import { BASE_URL_FN, STATIC_URL_FN } from '../config.js' // #ifdef APP-PLUS const sys = uni.getSystemInfoSync() let uploadPlugin = null if (sys.platform === 'android') { uploadPlugin = uni.requireNativePlugin('FileUpload') } // #endif /** * 文件选择、生成 formData 数据上传 */ export default class WkFile { constructor(params = {}) { if (['img', 'file'].includes(params.type)) { this.type = params.type } else { this.type = 'file' } this.fileList = [] this.filePathList = [] this.autoUpload = params.hasOwnProperty('autoUpload') ? params.autoUpload : true this.isAndroid = false // #ifdef APP-PLUS this.isAndroid = uni.getSystemInfoSync().platform === 'android' // #endif if (params.batchId) this.batchId = params.batchId } /** * 选择文件 */ choose() { const that = this return new Promise((resolve, reject) => { const chooseImage = () => { // 选择图片文件 uni.chooseImage({ count: 1, sizeType: ['original'], success: data => { console.log('choose data: ', data) that.fileList = data.tempFiles that.filePathList = data.tempFilePaths if (!that.autoUpload) { resolve(data) } else { that.uploadAll().then(res => { resolve(res) }).catch((error) => { console.log('choose uploadAll error:', error) reject(error) }) } }, fail: (error) => { reject(error) } }) } if (this.type === 'img') { chooseImage() } else { // 选择附件 // #ifdef H5 const oldEl = document.getElementById('fileHook') if (oldEl) { oldEl.parentNode.removeChild(oldEl) } const el = document.createElement('input') el.type = 'file' el.id = 'fileHook' el.style.display = 'none' el.onchange = evt => { console.log(evt.target.files) that.fileList = evt.target.files that.uploadAll().then(res => { resolve(res) }).catch((error) => { console.log('choose uploadAll error:', error) reject() }) } document.body.appendChild(el) el.click() // #endif // #ifdef APP-PLUS const sys = uni.getSystemInfoSync() if (that.isAndroid && uploadPlugin) { // Android that.androidChooseFile(path => { console.log('path: ', path) that.filePathList = [path] if (!that.autoUpload) { resolve(that.filePathList) } else { that.uploadAll().then(res => { resolve(res) }).catch((error) => { console.log('choose uploadAll error:', error) reject() }) } }) } else { // IOS 暂时不支持选择附件,使用选择图片代替 chooseImage() } // #endif // #ifndef APP-PLUS || H5 chooseImage() // #endif } }) } /** * android 选择附件 */ androidChooseFile(callbackFunc) { uploadPlugin.chooseFile( {}, data => { callbackFunc(data.path) } ) } /** * 上传单个文件 * @param {String} filePath 文件路径 */ androidUploadOne(filePath) { // if (filePath.startsWith('file://')) { // filePath = filePath.replace('file://', '') // } // if (!filePath.startsWith('/')) { // filePath = '/' + filePath // } return new Promise((resolve, reject) => { const formData = { type: this.type } if (this.batchId) { formData.batchId = this.batchId } const header = { 'Admin-Token': uni.getStorageSync('token') || '' } const appid = uni.getStorageSync('appid') || '' if (appid) { header.k = appid } uploadPlugin.upload( { url: BASE_URL_FN() + 'adminFile/upload', name: 'file', filePath: filePath, header, formData: formData, timeout: 5 * 60 }, res => { console.log('uplload res: ', res) resolve(res.data) }, (err) => { console.log('plugin upload error', err) reject('上传失败') } ) }) } /** * 上传单个文件 * @param {String} filePath 文件路径 */ uploadOne(data) { return new Promise((resolve, reject) => { const formData = { type: this.type } if (this.batchId) { formData.batchId = this.batchId } const header = { 'Admin-Token': uni.getStorageSync('token') || '' } const appid = uni.getStorageSync('appid') || '' if (appid) { header.k = appid } const requestConfig = { url: BASE_URL_FN() + 'adminFile/upload', fileType: 'image', name: 'file', header, formData: formData, success: res => { let data = res.data if (typeof res.data === 'string') { try { data = JSON.parse(res.data) } catch (e) { console.log('parse error: ', e) } } resolve(data.data || data) }, fail: (error) => { console.log('err', error) reject('上传失败') } } // #ifdef H5 if (typeof data === 'string') { requestConfig.filePath = data } else { requestConfig.file = data } // #endif // #ifndef H5 requestConfig.filePath = data // #endif console.log('upload config: ', requestConfig) uni.uploadFile(requestConfig) }) } /** * 批量上传文件 */ uploadAll() { return new Promise((resolve, reject) => { const that = this const arr = [] // #ifdef H5 if (this.type !== 'img') { this.fileList.forEach(file => { arr.push(that.uploadOne(file)) }) } else { this.filePathList.forEach(filePath => { arr.push(that.uploadOne(filePath)) }) } // #endif // #ifndef H5 if (this.isAndroid && uploadPlugin && this.type === 'file') { this.filePathList.forEach(filePath => { arr.push(that.androidUploadOne(filePath)) }) } else { this.filePathList.forEach(filePath => { arr.push(that.uploadOne(filePath)) }) } // #endif uni.showLoading({ mask: true, title: '加载中' }) Promise.all(arr).then(res => { console.log('uploadAll res', res) uni.hideLoading() resolve(res) }).catch((error) => { console.log('uploadAll err', error) uni.hideLoading() reject('批量上传失败') }) }) } } const $static = STATIC_URL_FN /** * 根据文件 url 获取文件相应类型的icon * @param url * @returns {*} */ export function calcIcon(url) { let temps = url ? url.split('.') : [] let ext = '' if (temps.length > 0) { ext = temps[temps.length - 1].toLowerCase() } else { ext = '' } // console.log('file type: ', ext) const typeMap = { img: { types: ['bmp', 'jpg', 'png', 'jpeg', 'gif', 'svg', 'webp'], icon: $static('images/file/file_img.png') }, excel: { types: ['xls', 'xlsx'], icon: $static('images/file/file_excel.png') }, ppt: { types: ['ppt', 'pptx'], icon: $static('images/file/file_ppt.png') }, word: { types: ['doc', 'docx'], icon: $static('images/file/file_word.png') }, pdf: { types: ['pdf'], icon: $static('images/file/file_pdf.png') }, txt: { types: ['txt', 'text'], icon: $static('images/file/file_txt.png') }, video: { types: ['mp4', 'mp3', 'avi', 'wmv', 'flv', 'rmvb'], icon: $static('images/file/file_video.png') }, zip: { types: ['rar', 'zip', '7z'], icon: $static('images/file/file_zip.png') }, } let res = Object.keys(typeMap).find(key => { return typeMap[key].types.includes(ext) }) if (res) return typeMap[res].icon return $static('images/file/file_unknown.png') } /** * 文件下载 * @param {Object} file * @param {String} file.url 文件 url 地址 * @param {String} file.name 文件名 eg: 1.txt */ export function downloadFile(file) { if (!file || !file.url) { uni.showToast({ title: '文件下载失败' }) return } let url = BASE_URL_FN() + (file.url.startsWith('/') ? file.url.replace('/', '') : file.url) let temps = file.name ? file.name.split('.') : [] let ext = '' if (temps.length > 0) { ext = temps[temps.length - 1].toLowerCase() } else { ext = '' } const token = uni.getStorageSync('token') || '' const appid = uni.getStorageSync('appid') || '' if ([ 'bmp', 'jpg', 'png', 'jpeg', 'gif', 'svg', 'webp' ].includes(ext)) { url = url + '?c=' + token if (appid) { url = url + '&k=' + appid } uni.previewImage({ urls: [url], indicator: 'number' }) return } uni.showLoading({ title: '正在加载..', mask: true }) const header = { 'Admin-Token': token } if (appid) { header.k = appid } uni.downloadFile({ url, header, success: res => { uni.hideLoading() // #ifdef H5 const el = document.createElement('a') el.href = res.tempFilePath el.download = file.name el.style.display = 'none' document.body.appendChild(el) el.click() el.parentNode.removeChild(el) // #endif // #ifndef H5 if ([ 'doc', 'xls', 'ppt', 'pdf', 'docx', 'xlsx', 'pptx' ].includes(ext)) { const sys = uni.getSystemInfoSync() let tempFilePath = res.tempFilePath if (sys.platform === 'ios') { tempFilePath = escape(tempFilePath) } uni.saveFile({ tempFilePath, success: res => { console.log('save success: ', res) uni.showToast({ title: '文件已保存至' + res.savedFilePath }) uni.openDocument({ filePath: res.savedFilePath, fileType: ext }) }, fail: error => { console.log('save error: ', error) uni.showToast({ title: '文件保存失败', icon: 'none' }) } }) } else { // #ifdef APP-PLUS plus.runtime.openFile(res.tempFilePath) // #endif // #ifdef MP-WEIXIN uni.showToast({ title: '该文件暂不支持预览' }) // #endif // #ifndef APP-PLUS | MP-WEIXIN uni.saveFile({ tempFilePath: res.tempFilePath, success: res => { console.log('save:', res) uni.showToast({ title: '文件已保存至' + res.savedFilePath }) }, fail: () => { uni.showToast({ title: '文件保存失败', icon: 'none' }) } }) // #endif } // #endif }, fail: () => { uni.hideLoading() uni.showToast({ title: '文件下载失败', icon: 'none' }) } }) }