Merge pull request #9047 from dataease/pr@dev@fixapi

Pr@dev@fixapi
This commit is contained in:
taojinlong 2024-04-10 18:30:09 +08:00 committed by GitHub
commit afb237da30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 3727 additions and 26 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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);
@ -188,16 +233,17 @@ public class ExportCenterService {
ExportTaskExample exportTaskExample = new ExportTaskExample();
ExportTaskExample.Criteria criteria = exportTaskExample.createCriteria();
criteria.andUserIdEqualTo(AuthUtils.getUser().getUserId());
exportTaskExample.setOrderByClause(" export_time desc ");
List<ExportTask> exportTasks = exportTaskMapper.selectByExample(exportTaskExample);
List<ExportTaskDTO> result = new ArrayList<>();
exportTasks.forEach(exportTask -> {
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);
});
@ -205,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()));
}
@ -214,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',
@ -3209,5 +3210,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: '搜索欄位',
@ -3201,5 +3202,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

@ -1806,6 +1806,7 @@ export default {
sub_axis_label: '副轴标签'
},
dataset: {
goto:', 前往 ',
scope_edit: '仅编辑时生效',
scope_all: '数据集预览时全局生效',
spend_time: '耗时',
@ -3202,5 +3203,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"
>{{ $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