fix: 导出中心导出失败时,给出失败原因信息,方便问题排查

This commit is contained in:
taojinlong 2024-06-14 15:28:33 +08:00
parent c0e267d2e5
commit 5eff932ce4
22 changed files with 497 additions and 368 deletions

View File

@ -3,8 +3,10 @@ package io.dataease.controller.exportCenter;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.dto.ExportTaskDTO;
import io.dataease.service.exportCenter.ExportCenterService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@ -16,8 +18,6 @@ public class ExportCenterController {
@Resource
private ExportCenterService exportCenterService;
@PostMapping("/exportTasks/{status}")
public List<ExportTaskDTO> exportTasks(@PathVariable String status) {
return exportCenterService.exportTasks(status);
@ -40,8 +40,8 @@ public class ExportCenterController {
}
@GetMapping("/download/{id}")
public void download(@PathVariable String id, HttpServletResponse response) throws Exception {
exportCenterService.download(id, response);
public ResponseEntity<org.springframework.core.io.Resource> download(@PathVariable String id, HttpServletResponse response, HttpServletRequest request) throws Exception {
return exportCenterService.download(id, response, request);
}
@PostMapping("/retry/{id}")

View File

@ -35,4 +35,4 @@ public class PgConfiguration extends JdbcConfiguration {
}
}
}
}

View File

@ -54,12 +54,19 @@ import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.InetAddress;
@ -148,22 +155,25 @@ public class ExportCenterService {
}
}
public void download(String id, HttpServletResponse response) throws Exception {
public ResponseEntity<org.springframework.core.io.Resource> download(String id, HttpServletResponse response, HttpServletRequest request) throws Exception {
ExportTask exportTask = exportTaskMapper.selectByPrimaryKey(id);
OutputStream outputStream = response.getOutputStream();
response.setContentType("application/vnd.ms-excel");
//文件名称
response.setHeader("Content-disposition", "attachment;filename=" + exportTask.getFileName());
InputStream fileInputStream = new FileInputStream(exportData_path + id + "/" + exportTask.getFileName());
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
try {
InputStreamResource resource = new InputStreamResource(new FileInputStream(exportData_path + id + "/" + exportTask.getFileName()));
String contentType = "application/octet-stream";
long contentLength = new File(exportData_path + id + "/" + exportTask.getFileName()).length(); // 如果有的话
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", exportTask.getFileName());
headers.setContentType(MediaType.parseMediaType(contentType));
if (contentLength > 0) {
headers.setContentLength(contentLength);
}
return ResponseEntity.ok()
.headers(headers)
.body(resource);
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
outputStream.flush();
outputStream.close();
fileInputStream.close();
response.flushBuffer();
}
public void delete(String id) {
@ -557,6 +567,7 @@ public class ExportCenterService {
setFileSize(dataPath + "/" + request.getViewName() + ".xlsx", exportTask);
} catch (Exception e) {
LogUtil.error("Failed to export data", e);
exportTask.setMsg(e.getMessage());
exportTask.setExportStatus("FAILED");
} finally {
exportTaskMapper.updateByPrimaryKey(exportTask);
@ -771,6 +782,7 @@ public class ExportCenterService {
setFileSize(dataPath + "/" + request.getFilename() + ".xlsx", exportTask);
} catch (Exception e) {
LogUtil.error("Failed to export data", e);
exportTask.setMsg(e.getMessage());
exportTask.setExportStatus("FAILED");
} finally {
exportTaskMapper.updateByPrimaryKey(exportTask);

View File

@ -0,0 +1 @@
ALTER TABLE `export_task` ADD COLUMN `msg` LONGTEXT NULL COMMENT '错误信息' AFTER `params`;

View File

@ -159,7 +159,7 @@
</span>
<el-button
v-if="showChartInfoType==='details'&& this.showChartInfo.dataFrom !== 'template' && hasDataPermission('export',panelInfo.privileges)"
v-if="showChartInfoType==='details'&& showChartInfo.dataFrom !== 'template' && hasDataPermission('export',panelInfo.privileges)"
size="mini"
:disabled="$store.getters.loadingMap[$store.getters.currentPath]"
@click="exportExcel"
@ -170,7 +170,7 @@
/>{{ $t('chart.export') }}Excel
</el-button>
<el-button
v-if="showChartInfoType==='details' && this.showChartInfo.dataFrom !== 'template' && !userId && hasDataPermission('export',panelInfo.privileges)"
v-if="showChartInfoType==='details' && showChartInfo.dataFrom !== 'template' && !userId && hasDataPermission('export',panelInfo.privileges)"
size="mini"
:disabled="$store.getters.loadingMap[$store.getters.currentPath] || dialogLoading"
@click="exportSourceDetails"

View File

@ -5,7 +5,7 @@
class="bg"
:style="customStyle"
>
<link-opt-bar/>
<link-opt-bar />
<Preview />
</div>
</template>

View File

@ -1,5 +1,5 @@
<template>
<div class="line-shape"></div>
<div class="line-shape" />
</template>
<script>

View File

@ -20,10 +20,9 @@
</template>
<script>
import {imgUrlTrans} from "@/components/canvas/utils/utils";
import { imgUrlTrans } from '@/components/canvas/utils/utils'
export default {
methods: {imgUrlTrans},
props: {
element: {
type: Object,
@ -53,7 +52,8 @@ export default {
}
return style
}
}
},
methods: { imgUrlTrans }
}
</script>

File diff suppressed because it is too large Load Diff

View File

@ -520,7 +520,7 @@ export default {
}
},
setTabLayout: _.debounce(function() {
this.headClassScroll = !!this.$refs?.deTabsConstom?.$refs?.tabsConstom?.$refs?.nav?.scrollable ? 'head-class-scroll' : ''
this.headClassScroll = this.$refs?.deTabsConstom?.$refs?.tabsConstom?.$refs?.nav?.scrollable ? 'head-class-scroll' : ''
}, 100),
calcTabLength() {
this.$nextTick(() => {

View File

@ -26,10 +26,13 @@ export default {
<div class="ai-popper-tips-content">
<p class="title">DataEase 智能客服</p>
<p class="constant">
你好我是 DataEase 智能客服<br />点击一下开启高效解答模式~<br />&nbsp;
你好我是 DataEase 智能客服<br>点击一下开启高效解答模式~<br>&nbsp;
</p>
<div class="bottom">
<el-button size="middle" @click="confirm"> 我知道了 </el-button>
<el-button
size="middle"
@click="confirm"
> 我知道了 </el-button>
</div>
</div>
<div slot="reference">

View File

@ -125,8 +125,15 @@
</div>
<ExportExcel ref="ExportExcelRef" />
<ai-tips @confirm="aiTipsConfirm" v-if="showOverlay" class="ai-icon-tips"></ai-tips>
<div v-if="showOverlay" class="overlay"></div>
<ai-tips
v-if="showOverlay"
class="ai-icon-tips"
@confirm="aiTipsConfirm"
/>
<div
v-if="showOverlay"
class="overlay"
/>
<ai-component
v-if="aiBaseUrl"
@ -167,7 +174,7 @@ import TemplateMarket from '@/views/panel/templateMarket'
import { changeFavicon, inOtherPlatform } from '@/utils/index'
import AiComponent from '@/layout/components/AiComponent'
import { findBaseParams } from '@/api/ai/aiComponent'
import AiTips from "@/layout/components/AiTips.vue";
import AiTips from '@/layout/components/AiTips.vue'
export default {
name: 'Topbar',
components: {
@ -313,7 +320,7 @@ export default {
})
},
methods: {
aiTipsConfirm(){
aiTipsConfirm() {
localStorage.setItem('DE1.0-AI-TIPS-CHECK', 'CHECKED')
this.showOverlay = false
},

View File

@ -8,7 +8,7 @@ let labelFormatter = null
export function baseLiquid(container, chart) {
let value = 0
const colors = []
let max, radius, bgColor, shape, labelContent, liquidStyle, originVal = 0
let max; let radius; let bgColor; let shape; let labelContent; let liquidStyle; let originVal = 0
if (chart.data?.series.length > 0) {
value = chart.data.series[0].data[0]
}

View File

@ -78,6 +78,7 @@
<div
v-if="scope.row.exportStatus==='FAILED'"
class="failed"
@click="showMsg(scope.row)"
>{{ $t("data_export.export_failed") }}</div>
<div
v-if="scope.row.exportStatus==='SUCCESS'"
@ -169,6 +170,14 @@
/>
</el-table>
</div>
<el-dialog
title="失败原因"
:visible.sync="msgDialogVisible"
append-to-body
width="30%"
>
<span>{{ msg }}</span>
</el-dialog>
</el-drawer>
</template>
<script>
@ -211,7 +220,9 @@ export default {
name: 'ALL'
}
],
loading: false
loading: false,
msgDialogVisible: false,
msg: ''
}
},
created() {
@ -436,6 +447,11 @@ export default {
}
this.handlerConfirm(options)
},
showMsg(item) {
this.msg = ''
this.msg = item.msg
this.msgDialogVisible = true
},
delAll() {
if (this.multipleSelection.length === 0) {
this.$confirm(this.$t('data_export.sure_del_all'), '', {
@ -547,6 +563,7 @@ export default {
font-weight: 400;
line-height: 20px;
color: #F54A45;
cursor: pointer;
}
.success {

View File

@ -27,7 +27,7 @@ import { queryPanelJumpInfo, queryTargetPanelJumpInfo } from '@/api/panel/linkJu
import { getNowCanvasComponentData, panelInit } from '@/components/canvas/utils/utils'
import { getOuterParamsInfo } from '@/api/panel/outerParams'
import { mapState } from 'vuex'
import {Base64} from "js-base64";
import { Base64 } from 'js-base64'
export default {
name: 'LinkView',

View File

@ -130,7 +130,10 @@
v-show="codeShow"
class="code"
>
<el-row class="code-contaniner" :class="isPad && 'is-pad'">
<el-row
class="code-contaniner"
:class="isPad && 'is-pad'"
>
<plugin-com
v-if="codeShow && loginTypes.includes(4) && codeIndex === 4"
ref="WecomQr"

View File

@ -1003,7 +1003,7 @@ export default {
this.sortTypeChange(this.localSortParams)
}
groupTree(this.groupForm, !userCache).then((res) => {
this.rootAuth = res.data ? res.data[0]?.privileges||'':''
this.rootAuth = res.data ? res.data[0]?.privileges || '' : ''
const resMainData = res.data ? res.data[0]?.children || [] : []
localStorage.setItem('panel-main-tree', JSON.stringify(resMainData))
if (!userCache) {

View File

@ -56,6 +56,7 @@ class DeWebsocket {
if (!this.isLoginStatus()) {
return
}
console.log(this.ws_url)
const socket = new SockJS(this.ws_url + '?userId=' + store.state.user.user.userId)
/* const socket = new SockJS('http://localhost:8081' + this.ws_url) */

View File

@ -27,6 +27,8 @@ public class ExportTask implements Serializable {
private String exportMachineName;
private String msg;
private String params;
private static final long serialVersionUID = 1L;

View File

@ -843,6 +843,76 @@ public class ExportTaskExample {
addCriterion("export_machine_name not between", value1, value2, "exportMachineName");
return (Criteria) this;
}
public Criteria andMsgIsNull() {
addCriterion("msg is null");
return (Criteria) this;
}
public Criteria andMsgIsNotNull() {
addCriterion("msg is not null");
return (Criteria) this;
}
public Criteria andMsgEqualTo(String value) {
addCriterion("msg =", value, "msg");
return (Criteria) this;
}
public Criteria andMsgNotEqualTo(String value) {
addCriterion("msg <>", value, "msg");
return (Criteria) this;
}
public Criteria andMsgGreaterThan(String value) {
addCriterion("msg >", value, "msg");
return (Criteria) this;
}
public Criteria andMsgGreaterThanOrEqualTo(String value) {
addCriterion("msg >=", value, "msg");
return (Criteria) this;
}
public Criteria andMsgLessThan(String value) {
addCriterion("msg <", value, "msg");
return (Criteria) this;
}
public Criteria andMsgLessThanOrEqualTo(String value) {
addCriterion("msg <=", value, "msg");
return (Criteria) this;
}
public Criteria andMsgLike(String value) {
addCriterion("msg like", value, "msg");
return (Criteria) this;
}
public Criteria andMsgNotLike(String value) {
addCriterion("msg not like", value, "msg");
return (Criteria) this;
}
public Criteria andMsgIn(List<String> values) {
addCriterion("msg in", values, "msg");
return (Criteria) this;
}
public Criteria andMsgNotIn(List<String> values) {
addCriterion("msg not in", values, "msg");
return (Criteria) this;
}
public Criteria andMsgBetween(String value1, String value2) {
addCriterion("msg between", value1, value2, "msg");
return (Criteria) this;
}
public Criteria andMsgNotBetween(String value1, String value2) {
addCriterion("msg not between", value1, value2, "msg");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -13,6 +13,7 @@
<result column="export_time" jdbcType="BIGINT" property="exportTime" />
<result column="export_pogress" jdbcType="VARCHAR" property="exportPogress" />
<result column="export_machine_name" jdbcType="VARCHAR" property="exportMachineName" />
<result column="msg" jdbcType="VARCHAR" property="msg" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.dataease.plugins.common.base.domain.ExportTask">
<result column="params" jdbcType="LONGVARCHAR" property="params" />
@ -77,7 +78,7 @@
</sql>
<sql id="Base_Column_List">
id, user_id, file_name, file_size, file_size_unit, export_from, export_status, export_from_type,
export_time, export_pogress, export_machine_name
export_time, export_pogress, export_machine_name, msg
</sql>
<sql id="Blob_Column_List">
params
@ -134,13 +135,13 @@
insert into export_task (id, user_id, file_name,
file_size, file_size_unit, export_from,
export_status, export_from_type, export_time,
export_pogress, export_machine_name, params
)
export_pogress, export_machine_name, msg,
params)
values (#{id,jdbcType=VARCHAR}, #{userId,jdbcType=BIGINT}, #{fileName,jdbcType=VARCHAR},
#{fileSize,jdbcType=DOUBLE}, #{fileSizeUnit,jdbcType=VARCHAR}, #{exportFrom,jdbcType=VARCHAR},
#{exportStatus,jdbcType=VARCHAR}, #{exportFromType,jdbcType=VARCHAR}, #{exportTime,jdbcType=BIGINT},
#{exportPogress,jdbcType=VARCHAR}, #{exportMachineName,jdbcType=VARCHAR}, #{params,jdbcType=LONGVARCHAR}
)
#{exportPogress,jdbcType=VARCHAR}, #{exportMachineName,jdbcType=VARCHAR}, #{msg,jdbcType=VARCHAR},
#{params,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.dataease.plugins.common.base.domain.ExportTask">
insert into export_task
@ -178,6 +179,9 @@
<if test="exportMachineName != null">
export_machine_name,
</if>
<if test="msg != null">
msg,
</if>
<if test="params != null">
params,
</if>
@ -216,6 +220,9 @@
<if test="exportMachineName != null">
#{exportMachineName,jdbcType=VARCHAR},
</if>
<if test="msg != null">
#{msg,jdbcType=VARCHAR},
</if>
<if test="params != null">
#{params,jdbcType=LONGVARCHAR},
</if>
@ -263,6 +270,9 @@
<if test="record.exportMachineName != null">
export_machine_name = #{record.exportMachineName,jdbcType=VARCHAR},
</if>
<if test="record.msg != null">
msg = #{record.msg,jdbcType=VARCHAR},
</if>
<if test="record.params != null">
params = #{record.params,jdbcType=LONGVARCHAR},
</if>
@ -284,6 +294,7 @@
export_time = #{record.exportTime,jdbcType=BIGINT},
export_pogress = #{record.exportPogress,jdbcType=VARCHAR},
export_machine_name = #{record.exportMachineName,jdbcType=VARCHAR},
msg = #{record.msg,jdbcType=VARCHAR},
params = #{record.params,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -301,7 +312,8 @@
export_from_type = #{record.exportFromType,jdbcType=VARCHAR},
export_time = #{record.exportTime,jdbcType=BIGINT},
export_pogress = #{record.exportPogress,jdbcType=VARCHAR},
export_machine_name = #{record.exportMachineName,jdbcType=VARCHAR}
export_machine_name = #{record.exportMachineName,jdbcType=VARCHAR},
msg = #{record.msg,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -339,6 +351,9 @@
<if test="exportMachineName != null">
export_machine_name = #{exportMachineName,jdbcType=VARCHAR},
</if>
<if test="msg != null">
msg = #{msg,jdbcType=VARCHAR},
</if>
<if test="params != null">
params = #{params,jdbcType=LONGVARCHAR},
</if>
@ -357,6 +372,7 @@
export_time = #{exportTime,jdbcType=BIGINT},
export_pogress = #{exportPogress,jdbcType=VARCHAR},
export_machine_name = #{exportMachineName,jdbcType=VARCHAR},
msg = #{msg,jdbcType=VARCHAR},
params = #{params,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -371,7 +387,8 @@
export_from_type = #{exportFromType,jdbcType=VARCHAR},
export_time = #{exportTime,jdbcType=BIGINT},
export_pogress = #{exportPogress,jdbcType=VARCHAR},
export_machine_name = #{exportMachineName,jdbcType=VARCHAR}
export_machine_name = #{exportMachineName,jdbcType=VARCHAR},
msg = #{msg,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -63,15 +63,11 @@
<table tableName="panel_link_ticket">
<table tableName="export_task">
<columnOverride column="msg" jdbcType="VARCHAR"/>
</table>
<!-- <table tableName="dataset_table_field">-->
<!-- <columnOverride column="origin_name" jdbcType="VARCHAR"/>-->
<!-- <columnOverride column="name" jdbcType="VARCHAR"/>-->
<!-- </table>-->
</context>
</generatorConfiguration>