zip批量导出
This commit is contained in:
parent
cc24edb8a9
commit
d7f7b85783
|
|
@ -228,49 +228,27 @@ export function downloadJson(url, params, filename, config) {
|
||||||
|
|
||||||
// 通用下载方法
|
// 通用下载方法
|
||||||
export function downloadZip(url, params, filename, config) {
|
export function downloadZip(url, params, filename, config) {
|
||||||
const backgroundMode = config && config.background === true
|
downloadLoadingInstance = Loading.service({
|
||||||
const showLoading = !(config && config.showLoading === false) && !backgroundMode
|
text: '正在下载数据,请稍候',
|
||||||
const finalAxiosConfig = {
|
spinner: 'el-icon-loading',
|
||||||
transformRequest: [
|
background: 'rgba(0, 0, 0, 0.7)',
|
||||||
(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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return service
|
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) => {
|
.then(async (data) => {
|
||||||
const isBlob = blobValidate(data)
|
const isBlob = blobValidate(data)
|
||||||
if (isBlob) {
|
if (isBlob) {
|
||||||
const blob = new Blob([data])
|
const blob = new Blob([data])
|
||||||
saveAs(blob, filename)
|
saveAs(blob, filename)
|
||||||
if (backgroundMode) {
|
|
||||||
Notification.success({
|
|
||||||
title: '导出完成',
|
|
||||||
message: 'ZIP 文件已准备好,正在开始下载。',
|
|
||||||
duration: 3000,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const resText = await data.text()
|
const resText = await data.text()
|
||||||
const rspObj = JSON.parse(resText)
|
const rspObj = JSON.parse(resText)
|
||||||
|
|
@ -278,20 +256,12 @@ export function downloadZip(url, params, filename, config) {
|
||||||
errorCode[rspObj.code] || rspObj.msg || errorCode['default']
|
errorCode[rspObj.code] || rspObj.msg || errorCode['default']
|
||||||
Message.error(errMsg)
|
Message.error(errMsg)
|
||||||
}
|
}
|
||||||
if (showLoading && downloadLoadingInstance) {
|
downloadLoadingInstance.close()
|
||||||
downloadLoadingInstance.close()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((r) => {
|
.catch((r) => {
|
||||||
console.error(r)
|
console.error(r)
|
||||||
if (r && r.message && r.message.includes('timeout')) {
|
Message.error('下载文件出现错误,请联系管理员!')
|
||||||
Message.error('导出超时,请减少选择数量或稍后重试')
|
downloadLoadingInstance.close()
|
||||||
} else {
|
|
||||||
Message.error('下载文件出现错误,请联系管理员!')
|
|
||||||
}
|
|
||||||
if (showLoading && downloadLoadingInstance) {
|
|
||||||
downloadLoadingInstance.close()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export default service
|
export default service
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,15 @@
|
||||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery" >查询</el-button>
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery" >查询</el-button>
|
||||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery" >重置</el-button>
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery" >重置</el-button>
|
||||||
<el-button type="success" icon="el-icon-download" size="mini" @click="exportExcel" :disabled="tableList.length === 0">导出Excel</el-button>
|
<el-button type="success" icon="el-icon-download" size="mini" @click="exportExcel" :disabled="tableList.length === 0">导出Excel</el-button>
|
||||||
<el-button type="success" icon="el-icon-download" size="mini" @click="exportZip" :disabled="tableList.length === 0">批量导出ZIP</el-button>
|
|
||||||
<el-button type="info" icon="el-icon-document-copy" size="mini" @click="showHistoryReportDialog">查看历史报表</el-button>
|
<el-button type="info" icon="el-icon-document-copy" size="mini" @click="showHistoryReportDialog">查看历史报表</el-button>
|
||||||
|
<el-button type="success" icon="el-icon-download" size="mini" @click="exportZip" :disabled="exporting">{{ exporting ? '导出中...' : '批量导出ZIP' }}</el-button>
|
||||||
|
<div v-if="exporting" class="progress-container">
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill" :style="{ width: progress + '%' }"></div>
|
||||||
|
</div>
|
||||||
|
<div class="progress-text">{{ progress }}% ({{ current }}/{{ totalZip }})</div>
|
||||||
|
<div class="status-text">{{ statusText }}</div>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
|
@ -568,6 +575,9 @@ import vueEasyPrint from "vue-easy-print";
|
||||||
import Treeselect from "@riophae/vue-treeselect";
|
import Treeselect from "@riophae/vue-treeselect";
|
||||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from 'xlsx';
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UnreportHome',
|
name: 'UnreportHome',
|
||||||
dicts: ['cost_status'],
|
dicts: ['cost_status'],
|
||||||
|
|
@ -664,7 +674,18 @@ export default {
|
||||||
proStatus:[
|
proStatus:[
|
||||||
{ id: 0, name: '未竣工' },
|
{ id: 0, name: '未竣工' },
|
||||||
{ id: 1, name: '已竣工' },
|
{ id: 1, name: '已竣工' },
|
||||||
]
|
],
|
||||||
|
|
||||||
|
|
||||||
|
//导出zip相关参数
|
||||||
|
exporting: false,
|
||||||
|
exportFlag: false,
|
||||||
|
progress: 0,
|
||||||
|
current: 0,
|
||||||
|
totalZip: 0,
|
||||||
|
statusText: '',
|
||||||
|
taskId: null,
|
||||||
|
pollInterval: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
@ -815,8 +836,32 @@ export default {
|
||||||
this.aform = { status: '2' };
|
this.aform = { status: '2' };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
//********************************************************************** */
|
||||||
//批量导出zip
|
//批量导出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) {
|
if (!this.ids.length) {
|
||||||
this.$message.error('请选择要导出的记录')
|
this.$message.error('请选择要导出的记录')
|
||||||
return false
|
return false
|
||||||
|
|
@ -825,19 +870,92 @@ export default {
|
||||||
this.ids.map(item => {
|
this.ids.map(item => {
|
||||||
param.push({ agreementId: item.agreementId,settlementType:item.settlementType })
|
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()
|
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){
|
openPrintDialog(row){
|
||||||
this.openPrint = true
|
this.openPrint = true
|
||||||
|
|
@ -1593,4 +1711,129 @@ export default {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-left: 1px solid #9c9c9c;
|
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;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- 为了让CSS生效,需要在组件的style部分添加以下样式 -->
|
||||||
|
<style scoped>
|
||||||
|
/* 优化的进度条样式 */
|
||||||
|
.progress-container.improved {
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
margin-top: 12px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
height: 10px;
|
||||||
|
background-color: #e4e7ed;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, #409eff 0%, #67c23a 100%);
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-indicator {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-info {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #409eff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加一些额外的动画效果 */
|
||||||
|
.progress-fill::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 50%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
||||||
|
animation: shimmer 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% {
|
||||||
|
left: -100%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
left: 200%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -250,6 +250,8 @@ export default {
|
||||||
keyWord: undefined,
|
keyWord: undefined,
|
||||||
proId: undefined,
|
proId: undefined,
|
||||||
jijuType: undefined,
|
jijuType: undefined,
|
||||||
|
startTime: undefined,
|
||||||
|
endTime: undefined
|
||||||
},
|
},
|
||||||
deviceRecordList: [], // 二级列表数据
|
deviceRecordList: [], // 二级列表数据
|
||||||
dialogDeviceTotal: 0, // 二级总条数
|
dialogDeviceTotal: 0, // 二级总条数
|
||||||
|
|
@ -353,6 +355,8 @@ export default {
|
||||||
this.dialogDeviceQuery.keyWord = ''
|
this.dialogDeviceQuery.keyWord = ''
|
||||||
this.dialogDeviceQuery.pageNum = 1
|
this.dialogDeviceQuery.pageNum = 1
|
||||||
this.dialogDeviceQuery.pageSize = 10
|
this.dialogDeviceQuery.pageSize = 10
|
||||||
|
this.dialogDeviceQuery.startTime = this.queryParams.startTime
|
||||||
|
this.dialogDeviceQuery.endTime = this.queryParams.endTime
|
||||||
this.deviceRecordList = []
|
this.deviceRecordList = []
|
||||||
this.getDeviceRecords()
|
this.getDeviceRecords()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue