fix:数据导出中心

This commit is contained in:
taojinlong 2024-04-10 18:26:37 +08:00
parent 9a55b2eb69
commit d7403a5e92
10 changed files with 180 additions and 26 deletions

View File

@ -34,6 +34,11 @@ public class ExportCenterController {
exportCenterService.delete(ids);
}
@PostMapping("/deleteAll/{type}")
public void deleteAll(@PathVariable String type){
exportCenterService.deleteAll(type);
}
@GetMapping("/download/{id}")
public void download(@PathVariable String id, HttpServletResponse response) throws Exception {
exportCenterService.download(id, response);

View File

@ -15,6 +15,7 @@ import io.dataease.dto.dataset.DataSetPreviewPage;
import io.dataease.dto.dataset.DataSetTableUnionDTO;
import io.dataease.i18n.Translator;
import io.dataease.plugins.common.base.domain.*;
import io.dataease.plugins.common.base.mapper.ChartViewMapper;
import io.dataease.plugins.common.base.mapper.DatasetTableMapper;
import io.dataease.plugins.common.base.mapper.DatasourceMapper;
import io.dataease.plugins.common.base.mapper.ExportTaskMapper;
@ -37,6 +38,8 @@ import io.dataease.service.dataset.*;
import io.dataease.service.datasource.DatasourceService;
import io.dataease.service.engine.EngineService;
import io.dataease.service.panel.PanelGroupService;
import io.dataease.websocket.entity.WsMessage;
import io.dataease.websocket.service.WsService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
@ -47,6 +50,7 @@ import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@ -68,6 +72,8 @@ import java.util.stream.Collectors;
@Service
public class ExportCenterService {
@Resource
private ChartViewMapper chartViewMapper;
@Resource
private ExportTaskMapper exportTaskMapper;
@Value("${export.dataset.limit:100000}")
@ -108,6 +114,9 @@ public class ExportCenterService {
private int keepAliveSeconds = 600;
private Map<String, Future> Running_Task = new HashMap<>();
@Autowired
private WsService wsService;
@PostConstruct
public void init() {
scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(corePoolSize);
@ -121,6 +130,16 @@ public class ExportCenterService {
Map.Entry<String, Future> entry = iterator.next();
if (entry.getValue().isDone()) {
iterator.remove();
try {
ExportTask exportTask = exportTaskMapper.selectByPrimaryKey(entry.getKey());
ExportTaskDTO exportTaskDTO = new ExportTaskDTO();
BeanUtils.copyBean(exportTaskDTO, exportTask);
setExportFromName(exportTaskDTO);
WsMessage message = new WsMessage(exportTask.getUserId(), "/task-export-topic", exportTaskDTO);
wsService.releaseMessage(message);
} catch (Exception e) {
}
}
}
}
@ -157,6 +176,32 @@ public class ExportCenterService {
exportTaskMapper.deleteByPrimaryKey(id);
}
public void deleteAll(String type) {
if (!STATUS.contains(type)) {
DataEaseException.throwException("无效的状态");
}
ExportTaskExample exportTaskExample = new ExportTaskExample();
ExportTaskExample.Criteria criteria = exportTaskExample.createCriteria();
criteria.andUserIdEqualTo(AuthUtils.getUser().getUserId());
if (!type.equalsIgnoreCase("ALL")) {
criteria.andExportStatusEqualTo(type);
}
List<ExportTask> exportTasks = exportTaskMapper.selectByExample(exportTaskExample);
exportTasks.parallelStream().forEach(exportTask -> {
Iterator<Map.Entry<String, Future>> iterator = Running_Task.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Future> entry = iterator.next();
if (entry.getKey().equalsIgnoreCase(exportTask.getId())) {
entry.getValue().cancel(true);
iterator.remove();
}
}
FileUtil.deleteDirectoryRecursively(exportData_path + exportTask.getId());
exportTaskMapper.deleteByPrimaryKey(exportTask.getId());
});
}
public void delete(List<String> ids) {
ids.forEach(id -> {
delete(id);
@ -195,10 +240,10 @@ public class ExportCenterService {
ExportTaskDTO exportTaskDTO = new ExportTaskDTO();
BeanUtils.copyBean(exportTaskDTO, exportTask);
if (status.equalsIgnoreCase("ALL")) {
setExportFromName(exportTaskDTO);
setExportFromAbsName(exportTaskDTO);
}
if (status.equalsIgnoreCase(exportTaskDTO.getExportStatus())) {
setExportFromName(exportTaskDTO);
setExportFromAbsName(exportTaskDTO);
}
result.add(exportTaskDTO);
});
@ -206,7 +251,7 @@ public class ExportCenterService {
return result;
}
private void setExportFromName(ExportTaskDTO exportTaskDTO) {
private void setExportFromAbsName(ExportTaskDTO exportTaskDTO) {
if (exportTaskDTO.getExportFromType().equalsIgnoreCase("chart")) {
exportTaskDTO.setExportFromName(panelGroupService.getAbsPath(exportTaskDTO.getExportFrom()));
}
@ -215,6 +260,16 @@ public class ExportCenterService {
}
}
private void setExportFromName(ExportTaskDTO exportTaskDTO) {
if (exportTaskDTO.getExportFromType().equalsIgnoreCase("chart")) {
exportTaskDTO.setExportFromName(chartViewMapper.selectByPrimaryKey(exportTaskDTO.getExportFrom()).getName());
}
if (exportTaskDTO.getExportFromType().equalsIgnoreCase("dataset")) {
exportTaskDTO.setExportFromName(datasetTableMapper.selectByPrimaryKey(exportTaskDTO.getExportFrom()).getName());
}
}
public void exportTableDetails(PanelViewDetailsRequest request, Workbook wb, CellStyle cellStyle, Sheet detailsSheet) throws IOException {
List<Object[]> details = request.getDetails();
Integer[] excelTypes = request.getExcelTypes();

View File

@ -488,7 +488,7 @@ export default {
const customClass = `de-message-loading de-message-export`;
this.$message({
message: h("p", null, [
"后台导出中,可前往",
this.$t('data_export.exporting'),
h(
Button,
{
@ -503,9 +503,9 @@ export default {
},
},
},
"数据导出中心",
this.$t('data_export.export_center'),
),
"查看进度,进行下载",
this.$t('data_export.export_info'),
]),
iconClass,
showClose: true,
@ -533,7 +533,7 @@ export default {
},
},
},
"数据导出中心",
this.$t('data_export.export_center'),
),
]),
iconClass,

View File

@ -765,7 +765,7 @@ export default {
const customClass = `de-message-loading de-message-export`;
this.$message({
message: h("p", null, [
"后台导出中,可前往",
this.$t('data_export.exporting'),
h(
Button,
{
@ -780,9 +780,9 @@ export default {
},
},
},
"数据导出中心",
this.$t('data_export.export_center'),
),
"查看进度,进行下载",
this.$t('data_export.export_info'),
]),
iconClass,
showClose: true,
@ -810,7 +810,7 @@ export default {
},
},
},
"数据导出中心",
this.$t('data_export.export_center'),
),
]),
iconClass,

View File

@ -538,6 +538,7 @@ export default {
confirm: 'Confirm'
},
deDataset: {
goto:', go to ',
search_by_name: 'Search by name',
new_folder: 'New Folder',
search_fields: 'Search Fields',
@ -3106,5 +3107,15 @@ export default {
geometry: 'Geometry',
onlinemap: 'Online map',
empty_desc: 'No map key'
},
data_export:{
export_center: 'Data Export Center',
export_info: 'View progress and download',
exporting: 'Exporting in the background, you can go to',
del_all: 'Delete all',
export_failed: 'Export failed',
export_from: 'Export source',
export_obj: 'Export object',
export_time: 'Export time'
}
}

View File

@ -538,6 +538,7 @@ export default {
confirm: '確 定'
},
deDataset: {
goto:', 前往 ',
search_by_name: '通過名稱搜索',
new_folder: '新建資料夾',
search_fields: '搜索欄位',
@ -3098,5 +3099,15 @@ export default {
geometry: '地理信息',
onlinemap: '在線地圖',
empty_desc: '暫無在線地圖key'
},
data_export:{
export_center: '資料匯出中心',
export_info: '查看進度,進行下載',
exporting: '後台匯出中,可前往',
del_all: '全部刪除',
export_failed: '匯出失敗',
export_from: '匯出來源',
export_obj: '匯出對象',
export_time: '匯出時間'
}
}

View File

@ -1704,6 +1704,7 @@ export default {
sub_axis_label: '副轴标签'
},
dataset: {
goto:', 前往 ',
scope_edit: '仅编辑时生效',
scope_all: '数据集预览时全局生效',
spend_time: '耗时',
@ -3100,5 +3101,15 @@ export default {
geometry: '地理信息',
onlinemap: '在线地图',
empty_desc: '暂无在线地图key'
},
data_export:{
export_center: '数据导出中心',
export_info: '查看进度,进行下载',
exporting: '后台导出中,可前往',
del_all: '全部删除',
export_failed: '导出失败',
export_from: '导出来源',
export_obj: '导出对象',
export_time: '导出时间'
}
}

View File

@ -497,7 +497,7 @@ export default {
const customClass = `de-message-loading de-message-export`;
this.$message({
message: h("p", null, [
"后台导出中,可前往",
this.$t('data_export.exporting'),
h(
Button,
{
@ -512,9 +512,9 @@ export default {
},
},
},
"数据导出中心",
this.$t('data_export.export_center'),
),
"查看进度,进行下载",
this.$t('data_export.export_info'),
]),
iconClass,
showClose: true,

View File

@ -1,7 +1,7 @@
<template>
<el-drawer
custom-class="de-user-drawer de-export-excel"
title="数据导出中心"
:title="$t('data_export.export_center')"
v-loading="drawerLoading"
:visible.sync="drawer"
direction="rtl"
@ -17,8 +17,11 @@
:name="tab.name"
></el-tab-pane>
</el-tabs>
<de-btn secondary icon="el-icon-delete" @click="delAll" :disabled="multipleSelection.length === 0"
>{{ $t("删除") }}
<de-btn secondary icon="el-icon-delete" @click="delAll" v-show="multipleSelection.length === 0"
>{{ $t("data_export.del_all") }}
</de-btn>
<de-btn secondary icon="el-icon-delete" @click="delAll" v-show="multipleSelection.length !== 0"
>{{ $t("commons.delete") }}
</de-btn>
<div class="table-container" :class="!tableData.length && 'hidden-bottom'">
<el-table
@ -28,13 +31,13 @@
style="width: 100%"
>
<el-table-column type="selection" width="50"> </el-table-column>
<el-table-column prop="fileName" label="文件名" width="332">
<el-table-column prop="fileName" :label="$t('driver.file_name')" width="332">
<template slot-scope="scope">
<div class="name-excel">
<svg-icon style="font-size: 24px;" icon-class="icon_file-excel_colorful"> </svg-icon>
<div class="name-content">
<div class="fileName">{{ scope.row.fileName }}</div>
<div class="failed" v-if="activeName==='FAILED'">导出失败</div>
<div class="failed" v-if="activeName==='FAILED'">{{ $t("data_export.export_failed") }}</div>
<div class="sucess" v-if="scope.row.exportStatus==='SUCCESS'">{{scope.row.fileSize}}{{scope.row.fileSizeUnit}}</div>
</div>
</div>
@ -42,20 +45,20 @@
<el-progress v-if="activeName==='IN_PROGRESS'" :percentage="+scope.row.exportPogress"></el-progress>
</template>
</el-table-column>
<el-table-column prop="exportFromName" label="导出对象" width="200">
<el-table-column prop="exportFromName" :label="$t('data_export.export_obj')" width="200">
</el-table-column>
<el-table-column prop="exportFromType" width="120" label="导出来源">
<el-table-column prop="exportFromType" width="120" :label="$t('data_export.export_from')">
<template slot-scope="scope">
<span v-if="scope.row.exportFromType === 'dataset'">数据集</span>
<span v-if="scope.row.exportFromType === 'chart'">视图</span>
<span v-if="scope.row.exportFromType === 'dataset'">{{ $t("dataset.datalist") }}</span>
<span v-if="scope.row.exportFromType === 'chart'">{{ $t("panel.view") }}</span>
</template>
</el-table-column>
<el-table-column prop="exportTime" width="180" label="导出时间">
<el-table-column prop="exportTime" width="180" :label="$t('data_export.export_time')">
<template slot-scope="scope">
<span>{{ scope.row.exportTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" prop="operate" width="80" label="操作">
<el-table-column fixed="right" prop="operate" width="80" :label="$t('commons.operating')">
<template slot-scope="scope">
<el-button v-if="scope.row.exportStatus === 'SUCCESS'" type="text" size="mini" @click="downloadClick(scope.row)">
<div class="download-export">
@ -92,6 +95,8 @@
import msgCfm from "@/components/msgCfm/index";
import request from "@/utils/request";
import {downloadFile, post} from '@/api/dataset/dataset'
import bus from "@/utils/bus";
import {Button} from "element-ui";
export default {
mixins: [msgCfm],
data() {
@ -131,6 +136,9 @@ export default {
created() {
this.handleClick()
},
mounted() {
bus.$on('task-export-topic-call', this.taskExportTopicCall)
},
methods: {
init() {
this.drawer = true;
@ -171,6 +179,46 @@ export default {
format(percentage) {
return '';
},
taskExportTopicCall(task){
if(JSON.parse(task).exportStatus === 'SUCCESS'){
this.openMessageLoading(JSON.parse(task).exportFromName + ' ' + this.$t('excel.export') + this.$t('dataset.completed')+ this.$t('dataset.goto'), 'success', this.callbackExport)
}
if(JSON.parse(task).exportStatus === 'FAILED'){
this.openMessageLoading(JSON.parse(task).exportFromName + ' ' + this.$t('excel.export') + this.$t('dataset.error')+ this.$t('dataset.goto'), 'error', this.callbackExport)
}
},
openMessageLoading(text, type, cb) {
const h = this.$createElement;
const iconClass = `el-icon-${type || 'success'}`
const customClass = `de-message-${type || 'success'} de-message-export`
this.$message({
message: h("p", null, [
this.$t(text),
h(
Button,
{
props: {
type: "text",
size: "mini",
},
class: "btn-text",
on: {
click: () => {
cb();
},
},
},
this.$t('data_export.export_center'),
)
]),
iconClass,
showClose: true,
customClass,
});
},
callbackExport() {
bus.$emit('data-export-center')
},
handleClick() {
this.tableData = []
this.drawerLoading = true
@ -255,7 +303,16 @@ export default {
},
delAll() {
if(this.multipleSelection.length === 0 ){
this.openMessageSuccess("请选择", 'error')
post(
'/exportCenter/deleteAll/' + this.activeName,
this.multipleSelection.map((ele) => ele.id),
true
).then(
(res) => {
this.handleClick()
}
)
this.openMessageSuccess("commons.delete_success");
return
}
post(

View File

@ -14,6 +14,10 @@ class DeWebsocket {
{
topic: '/web-seize-topic',
event: 'web-seize-topic-call'
},
{
topic: '/task-export-topic',
event: 'task-export-topic-call'
}
]
this.timer = null