vue 表格內容非同步匯出
阿新 • • 發佈:2020-12-21
在做表格匯出的時候,之前的框架一貫的做法是,匯出拿到頁面中快取的查詢條件,將條件引數在拼接,通過window.loaction的方式將引數拼接給後臺,在開啟,
// 匯出 handleExport() { if(this.total > this.exportLimit){ this.$_c.msg('匯出資料個數不能大於'+this.exportLimit,{type:'warning'}) return } if(this.url.export){ this.handleFieldsChangeBefore && thisView Code.handleFieldsChangeBefore() this.exportParams = this.$lockr.get('exportParams') || this.searchFields if(!this.exportParams.hasOwnProperty(this.exportTime[0]) || !this.exportParams.hasOwnProperty(this.exportTime[1])){//如果沒傳時間則預設查最近7天 if(!this.exportParams[this.exportTime[0]] || !this.exportParams[this.exportTime[1]]){ let now = new Date().getTime() this.exportParams[this.exportTime[0]] = now - 7*24*3600*1000 this.exportParams[this.exportTime[1]] = now } } this.initExportParams && this.initExportParams()this.downloadFileByUrl(this.url.export,this.exportParams,this.exportFileName) } }, /** * 通過Url下載檔案 * @param {String} url 下載路徑 * @param {Object} params 引數 * @param {String} fileName 檔名 */ export function downloadFileByUrl(url,params={},fileName="file") { url = process.env.VUE_APP_URL2 + url const keys = Object.keys(params) for(let i=0; i<keys.length; i++) { url = url + (i === 0 ? '?' : '&') + keys[i] + '=' + params[keys[i]] } url += (keys.length > 0 ? '&' : '?') + 'access_token=' + cookies.get('access_token') if (fileName) { var a = document.createElement('a'); // safari doesn't support this yet if (typeof a.download === 'undefined') { window.location = url } else { a.href = url; a.download = fileName; document.body.appendChild(a); a.click(); a.remove(); } } else { window.location = url; } }
但是在實際過程會有一個問題,就是資料量特別大的時候,就會等待很長的時間,才跳轉,如果這個時候一直點選匯出,可能導致系統崩潰問題
解決辦法:
非同步匯出,通過介面向後臺傳送查詢引數,後臺在返回一個標識,前段通過拿到的這個標識,進行輪詢,如果獲取到了路徑,就開啟並且關閉定時器
handleExport(val) { if(this.total > this.exportLimit){ this.$_c.msg('匯出資料個數不能大於'+this.exportLimit,{type:'warning'}) return } if (this.loadExcelTimer != null) { window.clearInterval(this.loadExcelTimer) this.loadExcelTimer = null } this.$loading.showLoading({text:'匯出中……'}) this.$ajax.post(this.url.export, this.exportParams).then(res => { if (res.code == 200) { this.loadExcelTimer = setInterval(() => { this.getAsyncExcel(res) }, 2000) } }).catch(err => { this.restInterval() this.$message.error('匯出失敗'); }) }, getAsyncExcel(result) { console.log('export table...') if (!result.data) return false this.$ajax.get(this.url.download, { id: result.data }).then(res => { if (res.data != null) { this.restInterval() //可以去下載了 let url = process.env.VUE_APP_URL2 + preUrl.files + res.data //建立下載連結 let link = document.createElement('a') //建立a標籤 link.style.display = 'none' //將a標籤隱藏 link.href = url //給a標籤新增下載連結 link.setAttribute('download', '檔案') //此處注意,要給a標籤新增一個download屬性,屬性值就是檔名稱,否則下載出來的檔案是沒有屬性的,空白白 document.body.appendChild(link) link.click() //執行a標籤 } }) },
完整的vue
<template> <TBLayout> <!-- search-form --> <content-box :slot="searchFormInfos.slot" :options="{width:'100%',padding:'20px 20px 0 20px'}"> <self-form :formInfos="searchFormInfos" :fields="searchFields" @setFields="changeFields" @button-click="handleButtonClick" /> </content-box> <btns-group slot="btnsgroup" :data="batchButtons" @button-click="handleButtonClick" v-if="isShowTable" /> <!-- table --> <self-table :slot="tableInfos.slot" v-if="isShowTable" :tableData="tableData" :tableInfos="tableInfos" :status="originBaseData" @selection-change="handleSelectionChange" @button-click="handleButtonClick" /> <!-- pager --> <self-pager slot="pager" @button-click="handleButtonClick" v-if="isShowTable"> <el-pagination :current-page="pageNum" :page-sizes="pageSizes" :page-size="pageSize" :layout="layout" :total="total" slot="pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange"> </el-pagination> </self-pager> <div slot="otherPager" class="chart-page" style="" v-if="!isShowTable"> <div class="echarts" ref="chart"></div> </div> </TBLayout> </template> <script> import echarts from 'echarts' import Crud from '@frameworks/assets/js/Crud' import TBLayout from '@modules/baselayout/views/TBLayout' import { searchFormInfos, batchButtons, tableInfos } from './PointHistory' import { preUrl } from '@frameworks/conf/api' import Api from '@frameworks/conf/api' import { formatDate } from '@frameworks/assets/js/Filters' export default { mixins: [Crud], components: { TBLayout }, data() { return { url: { getData: Api.getPageByTime, export: Api.exportHistory, download: Api.downLoadExcel }, detailParams: { url: '', params: {} }, methodGet: 'post', batchButtons, searchFormInfos: searchFormInfos, tableInfos: tableInfos, isShowTable: true,//是否展示表格 checkNodes: [],//樹選中的節點 chart: null, resizeTimer: null, chartOption: { title: { text: '趨勢圖' }, tooltip: { trigger: 'axis', appendToBody: true, formatter: (params) => { let format = "yyyy-MM-dd HH:mm:ss" let str = "" for (let i = 0; i < params.length; i++) { let p = params[i] let node = this.checkNodes[p.seriesIndex] let date = new Date(p.name) str += '<tr><td style="color:' + p.color + '">' + p.marker + "</td><td>" + p.seriesName + ":</td><td>" + p.value[1] + (p.data.unit || '') + "</td></tr>"; } str = "<p>" + formatDate(params[0].data.name, format) + "</p><table>" + str + "</table>"; return str }, axisPointer: { animation: false } }, xAxis: { type: 'time', splitLine: { show: false } }, yAxis: { name: '', type: 'value', boundaryGap: [0, '100%'], splitLine: { show: false } }, color: ['rgb(0, 137, 249)', 'rgb(0, 201, 134)', 'rgb(255, 132, 31)', 'rgb(216, 86, 207)', 'rgb(252, 206, 8)', 'rgb(133, 172, 193)'], series: [{ name: '模擬資料', type: 'line', showSymbol: false, hoverAnimation: false, data: [] }] }, exportLimit: 1000000, unit: '', loadExcelTimer: null } }, methods: { async handleSearchBefore() { let now = new Date().getTime() this.searchFields.startTime = now - 7 * 24 * 3600 * 1000 this.searchFields.endTime = now this.searchFormInfos.children[3].options.defaultValue = '' this.searchFields.tagNames = '' return await false }, handleFieldsChangeBefore() { delete this.searchFields.checkd delete this.searchFields.data delete this.searchFields.initDefault }, handleFieldsChangeAfter(val) { if (val.field.pointType) { this.searchFormInfos.children[3].options.pointType = val.field.pointType this.searchFields.tagNames = '' } else if (val.field.tagNames) { this.searchFormInfos.children[3].options.defaultValue = val.field.tagNames this.checkNodes = val.field.checkNodes || [] } }, //查 handleSearch(showMsg = false) { if (this.searchFields.showTypeData == 1) { this.isShowTable = true } else if (this.searchFields.showTypeData == 2) { this.isShowTable = false } if (!this.isShowTable) { this.$loading.showLoading() if (this.checkNodes && this.checkNodes.length > 10) { this.$_c.msg('曲線檢視選擇的測點不能超過10個,請重新選擇', { type: 'warning' }) this.$loading.hideLoading() return false } } this.handleFieldsChangeBefore && this.handleFieldsChangeBefore() //如果是曲線是查所有的資料,表格的是需要進行分頁的 let data = this.isShowTable ? Object.assign({ pageNum: this.startNum == 0 ? this.pageNum : this.startNum, pageSize: this.pageSize, }, this.searchFields) : this.searchFields //統一刪除showTypeData欄位 //delete data.showTypeData delete this.searchFields.checkNodes //獲取資料 this.$ajax.asyncAjax(this.url.getData, data, this.methodGet).then((res) => { if (res.code == 200) { //如果是表格 if (this.isShowTable) { this.startNum = 0 this.tableData = [] this.total = res.data.total ? res.data.total : 0 this.pageNum = res.data.pageNum ? res.data.pageNum : 1 this.pageCount = res.data.pages ? res.data.pages : 0 let result = this.isPager ? res.data[this.dataListField] : res.data if (result.length == 0 && this.pageNum != 1) {//如果最後一頁已經沒有資料,那就查前一頁 if (this.searchForwardCount < 1) { this.pageNum -= 1; this.searchForwardCount += 1; } else { this.pageNum = 1; } this.handleSearch(); return } this.tableData = this.parseSearchResult(result) //如果需要,把資料返回給父類 this.$emit('dto-data', res) //快取查詢條件 this.isSearchParamsToLocalStorage && this.setSearchFieldStorage() //獲取資料後對資料進行修飾 this.handleSearchSuccess && this.handleSearchSuccess(res, showMsg) } else {//曲線 this.initChart() this.initData(res) } } else { this.tableData = [] this.handleSearchFailed && this.handleSearchFailed(res) } this.searchForwardCount = 0; }).catch(res => { this.$loading.hideLoading() this.searchForwardCount = 0; this.tableData = [] this.handleSearchError && this.handleSearchError(res) }) if (this.clearSelection) this.handleSelectionChange() }, initChart() { this.chart = echarts.init(this.$refs.chart) this.chart.clear() this.chart.setOption(this.chartOption) this.chart.resize() }, handleExport(val) { if(this.total > this.exportLimit){ this.$_c.msg('匯出資料個數不能大於'+this.exportLimit,{type:'warning'}) return } if (this.loadExcelTimer != null) { window.clearInterval(this.loadExcelTimer) this.loadExcelTimer = null } this.$loading.showLoading({text:'匯出中……'}) // this.exportParams = { // startTime: 1607909692028, // endTime: 1608514492028, // pointType: 1, // tagNames: 'M0101.BL.ITCWSD_LTD_1,M0101.BL.ITCWSD_LTD_1.1.itEnvCCDownHum,M0101.BL.ITCWSD_LTD_1.1.itEnvCCDownTemp,M0101.BL.ITCWSD_LTD_1.1.itEnvCCIndex,M0101.BL.ITCWSD_LTD_1.1.itEnvCCUpHum', // showTypeData: 1, // rowNum: -1, // activeField: 'pointType', // timeZone: -8, // pageNum: 1, // pageSize: 10 // } this.$ajax.post(this.url.export, this.exportParams).then(res => { if (res.code == 200) { this.loadExcelTimer = setInterval(() => { this.getAsyncExcel(res) }, 2000) } }).catch(err => { this.restInterval() this.$message.error('匯出失敗'); }) }, getAsyncExcel(result) { console.log('export table...') if (!result.data) return false this.$ajax.get(this.url.download, { id: result.data }).then(res => { if (res.data != null) { this.restInterval() //可以去下載了 let url = process.env.VUE_APP_URL2 + preUrl.files + res.data //建立下載連結 let link = document.createElement('a') //建立a標籤 link.style.display = 'none' //將a標籤隱藏 link.href = url //給a標籤新增下載連結 link.setAttribute('download', '檔案') //此處注意,要給a標籤新增一個download屬性,屬性值就是檔名稱,否則下載出來的檔案是沒有屬性的,空白白 document.body.appendChild(link) link.click() //執行a標籤 } }) }, initData(result) { let rowData = result.data && result.data.list this.unit = rowData[0].unitName let legendArr = [], series = [] for (let item of this.checkNodes) { legendArr.push(item.name) } //首先遍歷一遍進行分組 for (let i = 0; i < this.checkNodes.length; i++) { let row = this.checkNodes[i] series.push( { name: legendArr[i] || row.id, type: 'line', showSymbol: false, hoverAnimation: false, data: this.getDataByCode(row, rowData) } ) } this.$loading.hideLoading() this.chart.setOption({ legend: { data: legendArr }, series }) this.chart.resize() }, //資料處理 getDataByCode(rowObj, rowData) { let dataArr = [] for (let i = 0; i < rowData.length; i++) { let row = rowData[i] let _arr = [] _arr.push(formatDate(row.time, 'yyyy-MM-dd HH:mm:ss')) _arr.push(row.value) rowObj.id == row.tagName && dataArr.push({ name: new Date(row.time), value: _arr, unit: row.unitName }) } return dataArr }, init() { window.onresize = () => { return (() => { if (this.resizeTimer) { clearTimeout(this.resizeTimer) } this.resizeTimer = setTimeout(() => { if (this.chart) { this.chart.resize(); } }, 300) })() } }, restInterval() { this.$loading.hideLoading() window.clearInterval(this.loadExcelTimer) this.loadExcelTimer = null } }, mounted() { this.init() }, activated() { this.searchFormInfos.children[3].options.pointType = '0' this.searchFields.tagNames = '' }, destroyed() { this.restInterval() }, }; </script> <style lang="scss"> @import '@frameworks/assets/css/common.scss'; .chart-page { box-shadow: 0 0 6px 1px rgba(0, 0, 0, 0.1); border-radius: 8px; height: 500px; padding: 20px; margin-right: 20px; } </style>View Code