From d7f7b85783767cd0c43a01d772d8decedf555fc6 Mon Sep 17 00:00:00 2001 From: hongchao <3228015117@qq.com> Date: Fri, 21 Nov 2025 15:07:52 +0800 Subject: [PATCH] =?UTF-8?q?zip=E6=89=B9=E9=87=8F=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/request.js | 66 ++--- .../material/cost/component/unreportHome.vue | 267 +++++++++++++++++- .../stquery/deviceComparisonStatistical.vue | 4 + 3 files changed, 277 insertions(+), 60 deletions(-) diff --git a/src/utils/request.js b/src/utils/request.js index 42269568..6ae46169 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -228,49 +228,27 @@ export function downloadJson(url, params, filename, config) { // 通用下载方法 export function downloadZip(url, params, filename, config) { - const backgroundMode = config && config.background === true - const showLoading = !(config && config.showLoading === false) && !backgroundMode - const finalAxiosConfig = { - transformRequest: [ - (params) => { - return params - }, - ], - headers: { 'Content-Type': 'application/json', encryptResponse: false }, - responseType: 'blob', - // if background mode and no explicit timeout, extend to 10 minutes - timeout: backgroundMode && !(config && typeof config.timeout === 'number') ? 600000 : undefined, - ...config, - } - - if (showLoading) { - downloadLoadingInstance = Loading.service({ - text: '正在下载数据,请稍候', - spinner: 'el-icon-loading', - background: 'rgba(0, 0, 0, 0.7)', - }) - } else if (backgroundMode) { - Notification.info({ - title: '已开始生成', - message: '批量导出任务已在后台执行,准备就绪后将自动下载。', - duration: 4000, - }) - } - + downloadLoadingInstance = Loading.service({ + text: '正在下载数据,请稍候', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)', + }) return service - .post(url, params, finalAxiosConfig) + .post(url, params, { + transformRequest: [ + (params) => { + return params + }, + ], + headers: { 'Content-Type': 'application/json',encryptResponse: false }, + responseType: 'blob', + ...config, + }) .then(async (data) => { const isBlob = blobValidate(data) if (isBlob) { const blob = new Blob([data]) saveAs(blob, filename) - if (backgroundMode) { - Notification.success({ - title: '导出完成', - message: 'ZIP 文件已准备好,正在开始下载。', - duration: 3000, - }) - } } else { const resText = await data.text() const rspObj = JSON.parse(resText) @@ -278,20 +256,12 @@ export function downloadZip(url, params, filename, config) { errorCode[rspObj.code] || rspObj.msg || errorCode['default'] Message.error(errMsg) } - if (showLoading && downloadLoadingInstance) { - downloadLoadingInstance.close() - } + downloadLoadingInstance.close() }) .catch((r) => { console.error(r) - if (r && r.message && r.message.includes('timeout')) { - Message.error('导出超时,请减少选择数量或稍后重试') - } else { - Message.error('下载文件出现错误,请联系管理员!') - } - if (showLoading && downloadLoadingInstance) { - downloadLoadingInstance.close() - } + Message.error('下载文件出现错误,请联系管理员!') + downloadLoadingInstance.close() }) } export default service diff --git a/src/views/material/cost/component/unreportHome.vue b/src/views/material/cost/component/unreportHome.vue index c67bf32a..8392e2f5 100644 --- a/src/views/material/cost/component/unreportHome.vue +++ b/src/views/material/cost/component/unreportHome.vue @@ -37,8 +37,15 @@ 查询 重置 导出Excel - 批量导出ZIP 查看历史报表 + {{ exporting ? '导出中...' : '批量导出ZIP' }} +
+
+
+
+
{{ progress }}% ({{ current }}/{{ totalZip }})
+
{{ statusText }}
+
@@ -568,6 +575,9 @@ import vueEasyPrint from "vue-easy-print"; import Treeselect from "@riophae/vue-treeselect"; import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import * as XLSX from 'xlsx'; +import request from '@/utils/request' + + export default { name: 'UnreportHome', dicts: ['cost_status'], @@ -664,7 +674,18 @@ export default { proStatus:[ { id: 0, name: '未竣工' }, { id: 1, name: '已竣工' }, - ] + ], + + + //导出zip相关参数 + exporting: false, + exportFlag: false, + progress: 0, + current: 0, + totalZip: 0, + statusText: '', + taskId: null, + pollInterval: null } }, created() { @@ -815,8 +836,32 @@ export default { this.aform = { status: '2' }; }, + + //********************************************************************** */ //批量导出zip - exportZip() { + // exportZip() { + // if (!this.ids.length) { + // this.$message.error('请选择要导出的记录') + // return false + // } + // let param = [] + // this.ids.map(item => { + // param.push({ agreementId: item.agreementId,settlementType:item.settlementType }) + // }) + // // exportLeaseAll(this.exportParams).then(res => { + // // downloadFile({ fileName: `月结明细_${new Date().getTime()}.zip`, fileData: res, fileType: 'application/zip;charset=utf-8' }) + // // }) + // this.downloadZip( + // 'material/slt_agreement_info/exportUnsettled', + // JSON.stringify(param), + // `未结算批量明细导出_${new Date().getTime()}.zip`, + // { background: true, showLoading: false, timeout: 600000 } + // ) + + // this.$refs.tableRef.clearSelection() + // }, + + async exportZip() { if (!this.ids.length) { this.$message.error('请选择要导出的记录') return false @@ -825,19 +870,92 @@ export default { this.ids.map(item => { param.push({ agreementId: item.agreementId,settlementType:item.settlementType }) }) - // exportLeaseAll(this.exportParams).then(res => { - // downloadFile({ fileName: `月结明细_${new Date().getTime()}.zip`, fileData: res, fileType: 'application/zip;charset=utf-8' }) - // }) - this.downloadZip( - 'material/slt_agreement_info/exportUnsettled', - JSON.stringify(param), - `未结算批量明细导出_${new Date().getTime()}.zip`, - { background: true, showLoading: false, timeout: 600000 } - ) + try { + this.exporting = true + this.progress = 0 + this.current = 0 + this.totalZip = 0 + this.statusText = '开始导出...' + + + const response = await request({ + url: '/material/slt_agreement_info/exportUnsettled', + method: 'post', + data: JSON.stringify(param), + timeout: 60000 // 设置10分钟超时 + }) + const result = response + this.taskId = result.taskId + this.totalZip = result.total + this.statusText = '导出任务已开始...' + this.exportFlag = true + // 开始轮询进度 + this.startPolling() + } catch (error) { + console.error('导出请求失败', error) + this.statusText = '导出请求失败' + this.exporting = false + } this.$refs.tableRef.clearSelection() }, + startPolling() { + this.pollInterval = setInterval(async () => { + try { + const response = await request({ + url: `/material/slt_agreement_info/exportProgress/${this.taskId}`, + method: 'get' + }) + const progress = response + + this.progress = progress.percentage + this.current = progress.current + + if (progress.status === 'completed') { + this.statusText = '导出完成,开始下载...' + clearInterval(this.pollInterval) + this.downloadFile() + this.exporting = false + this.exportFlag = false + } else if (progress.status === 'error') { + this.statusText = `导出失败: ${progress.errorMsg}` + clearInterval(this.pollInterval) + this.exporting = false + } else { + this.statusText = `处理中: ${progress.percentage}%` + } + } catch (error) { + console.error('查询进度失败', error) + this.statusText = '查询进度失败' + this.exportFlag = false + } + }, 1000) + }, + + downloadFile() { + if (this.taskId) { + console.log("xxxxxxxxxxtaskId",this.taskId) + const param = { taskId: this.taskId } + this.downloadZip( + 'material/slt_agreement_info/downloadExport', + JSON.stringify(param), + `未结算批量明细导出_${new Date().getTime()}.zip`, + ) + } + + }, + + beforeUnmount() { + if (this.pollInterval) { + clearInterval(this.pollInterval) + } + }, + + + + //********************************************************************** */ + openPrintDialog(row){ this.openPrint = true @@ -1593,4 +1711,129 @@ export default { text-align: center; border-left: 1px solid #9c9c9c; } + +//导出zip +.progress-container { + margin-top: 20px; + padding: 15px; + border: 1px solid #e0e0e0; + border-radius: 4px; +} + +.progress-bar { + width: 100%; + height: 20px; + background-color: #f0f0f0; + border-radius: 10px; + overflow: hidden; +} + +.progress-fill { + height: 100%; + background-color: #4CAF50; + transition: width 0.3s ease; +} + +.progress-text { + margin-top: 8px; + text-align: center; + font-size: 14px; + color: #666; +} + +.status-text { + margin-top: 5px; + text-align: center; + font-size: 12px; + color: #999; +} + +button:disabled { + opacity: 0.6; + cursor: not-allowed; +} +// + + + + \ No newline at end of file diff --git a/src/views/material/stquery/deviceComparisonStatistical.vue b/src/views/material/stquery/deviceComparisonStatistical.vue index b21fc72d..d8512c86 100644 --- a/src/views/material/stquery/deviceComparisonStatistical.vue +++ b/src/views/material/stquery/deviceComparisonStatistical.vue @@ -250,6 +250,8 @@ export default { keyWord: undefined, proId: undefined, jijuType: undefined, + startTime: undefined, + endTime: undefined }, deviceRecordList: [], // 二级列表数据 dialogDeviceTotal: 0, // 二级总条数 @@ -353,6 +355,8 @@ export default { this.dialogDeviceQuery.keyWord = '' this.dialogDeviceQuery.pageNum = 1 this.dialogDeviceQuery.pageSize = 10 + this.dialogDeviceQuery.startTime = this.queryParams.startTime + this.dialogDeviceQuery.endTime = this.queryParams.endTime this.deviceRecordList = [] this.getDeviceRecords() },