UNPKG

ci-plus

Version:

ci组件库

513 lines (485 loc) 20.1 kB
/** * @module downFile * @author : 卖女孩的小火柴 * !description : 下载文件方法 * @version : 1.0.2 * @since : 创建时间 2024-07-09 10:46:11 */ import { ElMessage } from 'element-plus' /** * 下载文件函数 * @param blob 文件数据,可以是Blob对象或BlobPart数组的一部分 * @param fileName 下载后的文件名 * 将给定的blob对象转换为文件,并提供一个下载链接以供用户下载。 * 如果blob对象是JSON格式,则尝试解析为JavaScript对象,并显示相应的错误消息。 * 如果解析失败,则直接以原始格式下载blob对象。 */ const downFileFn = function ( blob: Blob | BlobPart, fileName: string, resolve?: Function, reject?: Function ) { // 创建一个新的Blob对象,指定类型为application/json,假设blob是我们需要转换的Blob对象 let b = new Blob([blob], { type: 'application/json' }) // 创建一个FileReader对象用于读取Blob对象,创建一个新的FileReader实例 let reader = new FileReader() // 使用FileReader的readAsText方法读取Blob对象 以文本形式读取Blob对象 reader.readAsText(b) // 当数据读取完成时,处理结果 reader.onload = function (e) { let text = e?.target?.result // 获取到的text // console.log('text: ', text) // 尝试将读取的文本解析为JSON对象 try { let response = JSON.parse(text as string) console.log(response) // 这里是解析后object对象 ElMessage.error(response.msg) return reject && reject(response) } catch (error) { // 如果解析失败,将Blob对象转换为URL并创建下载链接 // console.error('Error parsing JSON', error) const url = URL.createObjectURL(new Blob([b])) let link: HTMLAnchorElement | null = document.createElement('a') link.href = url link.setAttribute('download', fileName) document.body.appendChild(link) link.click() ElMessage.success('操作成功,请打开浏览器自带下载器查看文件!') link = null resolve && resolve({ msg: '操作成功,请打开浏览器自带下载器查看文件!' }) } } // 如果在读取过程中出错 reader.onerror = function () { console.error('读取过程中出错.') } } type Obj = { [key: string]: any } interface Config { method?: string // 请求方法,默认为 GET | POST headers?: Object // 请求头 cbpercentage?: Function // 获取下载进度的回调函数 fileName?: string // 下载后的文件名 chunkSize?: number // 每次下载的块大小,默认为 10KB body?: string // 请求体 } const ajaxBox = { downFile: function (blob: Blob | BlobPart, fileName: string) { downFileFn(blob, fileName) }, // 下载文件 /** * 下载文件函数 * @param fillAddress string 表示服务端接口url地址 * @param fileName string 下载后的文件名 * @param method string 如果不想写get呢,你就写个null,但是你得写进去 * @param headers Object 请求头 * @param params Object 请求参数 * 将给定的blob对象转换为文件,并提供一个下载链接以供用户下载。 * 如果blob对象是JSON格式,则尝试解析为JavaScript对象,并显示相应的错误消息。 * 如果解析失败,则直接以原始格式下载blob对象。 */ downFileFetch: function ( fillAddress: string, fileName: string, method?: string, headers?: Obj, params?: Obj, cbpercentage?: Function ) { let options = { method: method || 'GET' } let _headers if (options.method === 'GET' || method === 'get') { _headers = { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' } } else if (options.method === 'POST' || method === 'post') { _headers = { 'Content-Type': 'application/json' //设置为json格式 } } // 判断请求是否为get请求,若是get请求,则将params参数拼接在url后面 if (method === 'GET') { const queryString = new URLSearchParams(params).toString() fillAddress = fillAddress + '?' + queryString } if (headers) { options['headers'] = headers || _headers } if ((method === 'post' || method === 'POST') && params) { options['body'] = JSON.stringify(params) } // 定义每次读取的数据块大小(字节) let chunkSize = 10240 // 例如,10KB // 如果在params中传递了chunkSize参数,则使用其值作为块大小 if (params && params.chunkSize) { chunkSize = params.chunkSize } // 初始化已下载的字节数 let downloaded = 0 // 初始化 Blob 切片起始点 let start = 0 fetch(fillAddress, options) .then((res) => { // console.log('resssssss: ', res) if (!res.ok) { throw new Error('Network response was not ok') } return res.blob() }) .then((blob) => { // console.log('blob: ', blob) const reader = new FileReader() // 创建 FileReader 对象 const readBlobInChunks = () => { // 创建一个 Blob 切片,大小为 chunkSize const chunkBlob = blob.slice(start, start + chunkSize) start += chunkSize // 更新起始点 // 读取 Blob 切片 reader.readAsArrayBuffer(chunkBlob) reader.onload = () => { // 累加已下载的字节数 // downloaded += reader.result.byteLength if (typeof reader.result === 'string' || reader.result === null) { console.log('reader.result不为 ArrayBuffer') // 处理字符串的情况,可能需要转换为 ArrayBuffer 或者其他处理逻辑 } else { downloaded += reader.result.byteLength } // 计算下载进度百分比 const total = blob.size const progress = ((downloaded / total) * 100).toFixed(2) cbpercentage && cbpercentage(progress) // 如果传递了获取下载进度的回调函数,则调用回调函数传递进度百分比 console.log(`下载进度: ${progress}%`) // 如果还有数据未读取,则继续读取 if (start < total) { readBlobInChunks() } else { console.log('下载完成.') // 处理下载完成的数据,例如将其保存或显示 // downFileFn(blob, fileName) downFileFn(blob, fileName) } } } readBlobInChunks() }) }, // 下载文件:2.0版本 /** * 下载文件函数 * @param url string 必传 表示服务端接口url地址 * @param params Obj 可选 请求参数 * @param config Config 可选 请求配置 * Config Config { method?: string, // 请求方法,默认为 GET | POST headers?: Object, // 请求头,默认值根据method方法判断 cbpercentage?: Function // 获取下载进度的回调函数 fileName?: string, // 下载后的文件名默认:'附件' chunkSize?: number, // 每次下载的块大小,默认为 10KB } * 将给定的blob对象转换为文件,并提供一个下载链接以供用户下载。 * 如果blob对象是JSON格式,则尝试解析为JavaScript对象,并显示相应的错误消息。 * 如果解析失败,则直接以原始格式下载blob对象。 */ downFileFetchV2: function (url: string, params?: Obj, config?: Config) { let options = { method: config?.method || 'GET' } let _headers let _fileName = config?.fileName || '附件' if (options.method === 'GET' || options.method === 'get') { _headers = { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' } } else if (options.method === 'POST' || options.method === 'post') { _headers = { 'Content-Type': 'application/json' // 设置为json格式 } } // 数组请求头: 优先使用传递的请求头,如果没有传递,则使用默认的请求头 options['headers'] = config?.headers || _headers // 判断请求是否为get请求,若是get请求,则将params参数拼接在url后面 if (options.method === 'GET') { const queryString = new URLSearchParams(params).toString() url = url + '?' + queryString } // 处理post请求的参数 if ((options.method === 'post' || options.method === 'POST') && params) { options['body'] = JSON.stringify(params) } // 定义每次读取的数据块大小(字节) let chunkSize = config?.chunkSize || 10240 // 例如,10KB // 初始化已下载的字节数 let downloaded = 0 // 初始化 Blob 切片起始点 let start = 0 return new Promise((resolve, reject) => { fetch(url, options) .then((res) => { // console.log('resssssss: ', res) if (!res.ok) { throw new Error('Network response was not ok') } return res.blob() }) .then((blob) => { // console.log('blob: ', blob) const reader = new FileReader() // 创建 FileReader 对象 const readBlobInChunks = () => { // 创建一个 Blob 切片,大小为 chunkSize const chunkBlob = blob.slice(start, start + chunkSize) start += chunkSize // 更新起始点 // 读取 Blob 切片 reader.readAsArrayBuffer(chunkBlob) reader.onload = () => { // 累加已下载的字节数 // downloaded += reader.result.byteLength if (typeof reader.result === 'string' || reader.result === null) { console.log('reader.result不为 ArrayBuffer') // 处理字符串的情况,可能需要转换为 ArrayBuffer 或者其他处理逻辑 } else { downloaded += reader.result.byteLength } // 计算下载进度百分比 const total = blob.size const progress = ((downloaded / total) * 100).toFixed(2) config?.cbpercentage && config?.cbpercentage(progress) // 如果传递了获取下载进度的回调函数,则调用回调函数传递进度百分比 console.log(`下载进度: ${progress}%`) // 如果还有数据未读取,则继续读取 if (start < total) { readBlobInChunks() } else { console.log('下载完成.') // 处理下载完成的数据,例如将其保存或显示 downFileFn(blob, _fileName) // resolve(true) } } } readBlobInChunks() }) .catch((error) => { console.error('下载文件时出错:', error) reject(error) }) }) }, // 下载文件:3.0版本:优先使用传递的文件名,若不传递文件问就使用后端返回的文件名 downFileFetchV3: function (url: string, params?: Obj, config?: Config) { let options: any = { method: config?.method || 'GET' } let _headers let _fileName = '' if (options.method === 'GET' || options.method === 'get') { _headers = { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' } } else if (options.method === 'POST' || options.method === 'post') { _headers = { 'Content-Type': 'application/json' // 设置为json格式 } } // 数组请求头: 优先使用传递的请求头,如果没有传递,则使用默认的请求头 options['headers'] = config?.headers || _headers // 判断请求是否为get请求,若是get请求,则将params参数拼接在url后面 if (options.method === 'GET') { const queryString = new URLSearchParams(params).toString() url = url + '?' + queryString } // 处理post请求的参数 if ((options.method === 'post' || options.method === 'POST') && params) { options['body'] = JSON.stringify(params) } // 定义每次读取的数据块大小(字节) let chunkSize = config?.chunkSize || 10240 // 例如,10KB // 初始化已下载的字节数 let downloaded = 0 // 初始化 Blob 切片起始点 let start = 0 return new Promise((resolve, reject) => { fetch(url, options) .then((res: any) => { if (config?.fileName && res.ok) { // 如果传递了文件名,则直接返回 Blob _fileName = config?.fileName || '附件.xlsx' return res.blob().then((blob: Blob) => ({ blob, _fileName })) } else if (!config?.fileName && res.ok) { // 如果没传递文件名,则使后端返回文件名 // 获取响应头中的 Content-Disposition(此属性中包含文件名)如:'attachment; filename="测试文件.xlsx"' const contentDisposition = res.headers.get('Content-Disposition') console.log('后端返回的文件名字符串: ', contentDisposition) if (contentDisposition) { // 解析文件名 const fileNameMatch = contentDisposition.match(/filename="(.+)"/) || // attachment; filename="文件名.xlsx" 匹配文件名带双引号 contentDisposition.match(/filename='(.+)'/) || // attachment; filename='文件名.xlsx' 匹配文件名带单引号 contentDisposition.match(/filename=(?:([^;]+))/) || // attachment; filename=文件名.xlsx 匹配文件名不带引号 contentDisposition.match(/filename\*=utf-8''(.+)/) || // attachment; filename*=utf-8''文件名.xlsx contentDisposition.match(/filename=(?:"([^"]+)"|'([^']+)'|([^;]+))/) //匹配文件名带双引号、单引号、不带引号 // console.log('文件名数组: ', fileNameMatch) if (fileNameMatch.length > 1) { // 匹配到文件名,则将文件名解码并赋值给 _fileName _fileName = decodeURIComponent( fileNameMatch[1] || fileNameMatch[2] || fileNameMatch[3] ) console.log('后端返回的文件名: ', _fileName) return res.blob().then((blob: Blob) => ({ blob, _fileName })) } } } if (!res.ok) { console.log('res: ', res) throw new Error('网络响应不正常!或其他错误') } // 如果没有找到文件名,直接返回 Blob return res.blob().then((blob: Blob) => ({ blob, _fileName })) }) .then(({ blob, _fileName }) => { // console.log('blob: ', blob, _fileName) const reader = new FileReader() // 创建 FileReader 对象 const readBlobInChunks = () => { // 创建一个 Blob 切片,大小为 chunkSize const chunkBlob = blob.slice(start, start + chunkSize) start += chunkSize // 更新起始点 // 读取 Blob 切片 reader.readAsArrayBuffer(chunkBlob) reader.onload = () => { // 累加已下载的字节数 // downloaded += reader.result.byteLength if (typeof reader.result === 'string' || reader.result === null) { console.log('reader.result不为 ArrayBuffer') // 处理字符串的情况,可能需要转换为 ArrayBuffer 或者其他处理逻辑 } else { downloaded += reader.result.byteLength } // 计算下载进度百分比 const total = blob.size const progress = ((downloaded / total) * 100).toFixed(2) config?.cbpercentage && config?.cbpercentage(progress) // 如果传递了获取下载进度的回调函数,则调用回调函数传递进度百分比 console.log(`下载进度: ${progress}%`) // 如果还有数据未读取,则继续读取 if (start < total) { readBlobInChunks() } else { console.log('下载完成.') // 处理下载完成的数据,例如将其保存或显示 downFileFn(blob, _fileName, resolve, reject) // resolve(true) } } } readBlobInChunks() }) .catch((error) => { console.error('下载文件时出错:', error) reject(error) }) }) } /* sendJSONP: function (url, callbackName, callback) { const script = document.createElement('script'); // 设置script元素的src属性,拼接callback参数 script.src = `${url}?callback=${callbackName}`; // 将script元素添加到页面中 document.body.appendChild(script); // 定义全局的回调函数,用于接收JSONP响应 window[callbackName] = function (data) { // 执行传入的回调函数,并将JSONP响应作为参数传递 callback(data); // 执行完毕后移除script元素 document.body.removeChild(script); // 删除全局的回调函数 delete window[callbackName]; }; }, */ } export default ajaxBox /** * 使用下载示例 get const exportFile = () => { let rowData = InventoryTableRef.value!.getSelectionRows() const url = storageModule + 'storage_standing_book_batch_export_get/' const headers = { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', } const params = { ids: JSON.stringify(rowData.map((v: { id: any }) => v.id)), state: 1, org_id: UserData.orgId, storage_type: 'CAILIAO', } CiPlus.Fn.ajaxBox.downFileFetch( url, '材料库_库存台账数据.xlsx', 'GET', headers, params, ) } 使用下载示例 post const exportFile = () => { const loading = ElLoading.service({ lock: true, text: 'Loading', background: 'rgba(0, 0, 0, 0.7)', }) // 打开加载中 let rowData = WeighingTableRef.value!.getSelectionRows() const url = storageModule + 'weighing_record_batch_export_post/' const headers = { 'Content-Type': 'application/json', //设置为json格式 } const params = { ids: rowData.map((v: { id: any }) => v.id), // 直接数组形式 state: 1, org_id: UserData.orgId, } console.log('params', params) CiPlus.Fn.ajaxBox.downFileFetch( url, '称重记录数据(批次).xlsx', 'POST', headers, params, ).then((result) => { console.log('result: ', result) }) .catch((err) => { console.log('err: ', err) }) .finally(() => { loading.close() // 关闭加载中 }) } // 版本3.0:提供了.then和.catch方法,可以更方便地处理异步操作的结果和错误。 const loading = ElLoading.service({ lock: true, text: 'Loading', background: 'rgba(0, 0, 0, 0.7)', }) const url = CrossAuditModule + 'generate_report_get/' const params = { ids: ids, } ajaxBox .downFileFetchV3(url, params, { method: 'POST', }) .then((res) => { console.log('成功: ', res) }) .catch((err) => { console.log('失败: ', err) }).finally(() => { loading.close() // 关闭加载中 }) */