feat(图表): 支持在视图侧导出视图原始明细数据 #5894

This commit is contained in:
wangjiahao 2024-04-25 14:48:37 +08:00
parent 1e8729918b
commit 73c5a8c371
10 changed files with 197 additions and 68 deletions

View File

@ -12,6 +12,7 @@ import io.dataease.commons.constants.DePermissionType;
import io.dataease.commons.constants.PanelConstants;
import io.dataease.commons.constants.ResourceAuthLevel;
import io.dataease.controller.handler.annotation.I18n;
import io.dataease.controller.request.dataset.DataSetExportRequest;
import io.dataease.controller.request.panel.*;
import io.dataease.dto.PermissionProxy;
import io.dataease.dto.authModel.VAuthModelDTO;
@ -155,6 +156,13 @@ public class PanelGroupController {
return panelGroupService.queryPanelComponents(id);
}
@ApiOperation("视图导出数据集明细")
@PostMapping("/exportDatasetDetails")
@I18n
public void exportDatasetDetails(@RequestBody PanelViewDetailsRequest request, HttpServletResponse response) throws Exception {
panelGroupService.exportDatasetDetails(request, response);
}
@ApiOperation("公共连接导出仪表板视图明细")
@PostMapping("/exportDetails")
@I18n
@ -172,8 +180,13 @@ public class PanelGroupController {
@PostMapping("/innerExportDetails")
@DePermissionProxy(value = "proxy")
@I18n
public void innerExportDetails(@RequestBody PanelViewDetailsRequest request) throws IOException {
exportCenterService.addTask(request.getViewId(), "chart", request);
public void innerExportDetails(@RequestBody PanelViewDetailsRequest request) throws Exception {
if("dataset".equals(request.getDownloadType())){
DataSetExportRequest exportRequest = panelGroupService.composeDatasetExportRequest(request);
exportCenterService.addTask(exportRequest.getId(), "dataset", exportRequest);
}else{
exportCenterService.addTask(request.getViewId(), "chart", request);
}
}
@ApiOperation("更新仪表板状态")

View File

@ -10,6 +10,7 @@ import io.dataease.commons.constants.*;
import io.dataease.commons.utils.*;
import io.dataease.controller.request.authModel.VAuthModelRequest;
import io.dataease.controller.request.chart.ChartExtRequest;
import io.dataease.controller.request.dataset.DataSetExportRequest;
import io.dataease.controller.request.dataset.DataSetTableRequest;
import io.dataease.controller.request.panel.*;
import io.dataease.dto.DatasourceDTO;
@ -32,6 +33,9 @@ import io.dataease.plugins.common.base.domain.*;
import io.dataease.plugins.common.base.mapper.*;
import io.dataease.plugins.common.constants.DeTypeConstants;
import io.dataease.plugins.common.exception.DataEaseException;
import io.dataease.plugins.common.request.chart.ChartExtFilterRequest;
import io.dataease.plugins.common.request.permission.DatasetRowPermissionsTreeItem;
import io.dataease.plugins.common.request.permission.DatasetRowPermissionsTreeObj;
import io.dataease.plugins.common.util.HttpClientUtil;
import io.dataease.service.chart.ChartViewService;
import io.dataease.service.dataset.DataSetGroupService;
@ -144,6 +148,9 @@ public class PanelGroupService {
@Resource
private DatasourceMapper datasourceMapper;
@Resource
private DatasetTableMapper datasetTableMapper;
@Value("${export.views.limit:100000}")
private Long limit;
@ -657,6 +664,72 @@ public class PanelGroupService {
CacheUtils.removeAll(AuthConstants.DEPT_PANEL_NAME);
}
public DataSetExportRequest composeDatasetExportRequest(PanelViewDetailsRequest request){
ChartExtRequest extRequest = request.getComponentFilterInfo();
List<ChartExtFilterRequest> filter = new ArrayList();
if(extRequest != null){
if(CollectionUtils.isNotEmpty(extRequest.getFilter())){
filter.addAll(extRequest.getFilter());
}if(CollectionUtils.isNotEmpty(extRequest.getLinkageFilters())){
filter.addAll(extRequest.getLinkageFilters());
}if(CollectionUtils.isNotEmpty(extRequest.getOuterParamsFilters())){
filter.addAll(extRequest.getOuterParamsFilters());
}
}
Gson gson = new Gson();
DatasetRowPermissionsTreeObj permissionsTreeObjFilter = new DatasetRowPermissionsTreeObj();
permissionsTreeObjFilter.setLogic("and");
List<DatasetRowPermissionsTreeItem> composePermission = new ArrayList<>();
permissionsTreeObjFilter.setItems(composePermission);
if(CollectionUtils.isNotEmpty(filter)){
filter.forEach(filterInfo ->{
DatasetRowPermissionsTreeItem filterPermission = new DatasetRowPermissionsTreeItem();
List<String> values = filterInfo.getValue();
String operator = filterInfo.getOperator();
String dataSetFilterType = "logic";
String term = operator;
if("eq".equals(operator) && values.size()>1){
dataSetFilterType = "enum";
}
String fieldId = filterInfo.getFieldId();
filterPermission.setFieldId(fieldId);
filterPermission.setFilterType(dataSetFilterType);
filterPermission.setType("item");
if(dataSetFilterType.equals("enum")){
filterPermission.setEnumValue(values);
}else{
filterPermission.setTerm(term);
filterPermission.setValue(values.get(0));
}
composePermission.add(filterPermission);
});
}
ChartViewWithBLOBs chartInfo = chartViewMapper.selectByPrimaryKey(request.getViewId());
String customFilter = chartInfo.getCustomFilter();
DatasetTable datasetTable = datasetTableMapper.selectByPrimaryKey(chartInfo.getTableId());
DataSetExportRequest dataSetExportRequest = new DataSetExportRequest();
BeanUtils.copyBean(dataSetExportRequest,datasetTable);
if(CollectionUtils.isNotEmpty(composePermission)){
DatasetRowPermissionsTreeObj permissionsTreeObjCustomsFilter = gson.fromJson(customFilter,DatasetRowPermissionsTreeObj.class);
DatasetRowPermissionsTreeItem customFilterPermission = new DatasetRowPermissionsTreeItem();
customFilterPermission.setType("tree");
customFilterPermission.setSubTree(permissionsTreeObjCustomsFilter);
composePermission.add(customFilterPermission);
dataSetExportRequest.setExpressionTree(gson.toJson(permissionsTreeObjFilter));
}else{
dataSetExportRequest.setExpressionTree(customFilter);
}
dataSetExportRequest.setFilename(dataSetExportRequest.getName());
return dataSetExportRequest;
}
public void exportDatasetDetails(PanelViewDetailsRequest request, HttpServletResponse response) throws Exception {
dataSetTableService.exportDataset(composeDatasetExportRequest(request),response);
}
public void exportPanelViewDetails(PanelViewDetailsRequest request, HttpServletResponse response) throws IOException {
OutputStream outputStream = response.getOutputStream();

View File

@ -269,6 +269,15 @@ export function innerExportDetails(data) {
})
}
export function exportDatasetDetails(data) {
return request({
url: 'panel/group/exportDatasetDetails',
method: 'post',
data: data,
loading: true
})
}
export function updatePanelStatus(panelId, param) {
return request({
url: '/panel/group/updatePanelStatus/' + panelId,

View File

@ -206,7 +206,7 @@ import { uploadFileResult } from '@/api/staticResource/staticResource'
import eventBus from '@/components/canvas/utils/eventBus'
import { hasDataPermission } from '@/utils/permission'
import { exportExcelDownload } from '@/components/canvas/utils/utils'
import { Button } from "element-ui";
import { Button } from 'element-ui'
export default {
components: { Background, LinkJumpSet, FieldsList, SettingMenu, LinkageField, MapLayerController },
@ -476,73 +476,73 @@ export default {
}
if (val && val.success === false) {
this.openMessageSuccess( `${this.chart.title ? this.chart.title : this.chart.name} 导出失败,前往`, 'error',this.exportData);
this.openMessageSuccess(`${this.chart.title ? this.chart.title : this.chart.name} 导出失败,前往`, 'error', this.exportData)
}
},
exportData() {
bus.$emit('data-export-center')
},
openMessageLoading(cb) {
const h = this.$createElement;
const iconClass = `el-icon-loading`;
const customClass = `de-message-loading de-message-export`;
const h = this.$createElement
const iconClass = `el-icon-loading`
const customClass = `de-message-loading de-message-export`
this.$message({
message: h("p", null, [
message: h('p', null, [
this.$t('data_export.exporting'),
h(
Button,
{
props: {
type: "text",
size: "mini",
type: 'text',
size: 'mini'
},
class: "btn-text",
class: 'btn-text',
on: {
click: () => {
cb();
},
},
cb()
}
}
},
this.$t('data_export.export_center'),
this.$t('data_export.export_center')
),
this.$t('data_export.export_info'),
this.$t('data_export.export_info')
]),
iconClass,
showClose: true,
customClass,
});
customClass
})
},
openMessageSuccess(text, type, cb) {
const h = this.$createElement;
const iconClass = `el-icon-${type || "success"}`;
const customClass = `de-message-${type || "success"} de-message-export`;
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, [
h("span", null, text),
message: h('p', null, [
h('span', null, text),
h(
Button,
{
props: {
type: "text",
size: "mini",
type: 'text',
size: 'mini'
},
class: "btn-text",
class: 'btn-text',
on: {
click: () => {
cb();
},
},
cb()
}
}
},
this.$t('data_export.export_center'),
),
this.$t('data_export.export_center')
)
]),
iconClass,
showClose: true,
customClass,
});
customClass
})
},
exportExcelDownload() {
exportExcelDownload(this.chart, null, null, null, null, this.exportDataCb)
exportExcelDownload(this.chart, null, null, null, null, null, this.exportDataCb)
},
auxiliaryMatrixChange() {
if (this.curComponent.auxiliaryMatrix) {

View File

@ -202,6 +202,18 @@
class="ds-icon-excel"
/>{{ $t('chart.export') }}Excel
</el-button>
<el-button
v-if="showChartInfoType==='details' && hasDataPermission('export',panelInfo.privileges)"
size="mini"
:disabled="$store.getters.loadingMap[$store.getters.currentPath] || dialogLoading"
@click="exportSourceDetails"
>
<svg-icon
icon-class="ds-excel"
class="ds-icon-excel"
/>{{ $t('chart.') }}
</el-button>
</span>
<user-view-dialog
v-if="chartDetailsVisible"
@ -239,7 +251,7 @@ import ChartComponent from '@/views/chart/components/ChartComponent.vue'
import TableNormal from '@/views/chart/components/table/TableNormal'
import LabelNormal from '../../../views/chart/components/normal/LabelNormal'
import { uuid } from 'vue-uuid'
import { Button } from "element-ui";
import { Button } from 'element-ui'
import bus from '@/utils/bus'
import { mapState } from 'vuex'
import { isChange } from '@/utils/conditionUtil'
@ -760,63 +772,63 @@ export default {
bus.$emit('data-export-center')
},
openMessageLoading(cb) {
const h = this.$createElement;
const iconClass = `el-icon-loading`;
const customClass = `de-message-loading de-message-export`;
const h = this.$createElement
const iconClass = `el-icon-loading`
const customClass = `de-message-loading de-message-export`
this.$message({
message: h("p", null, [
message: h('p', null, [
this.$t('data_export.exporting'),
h(
Button,
{
props: {
type: "text",
size: "mini",
type: 'text',
size: 'mini'
},
class: "btn-text",
class: 'btn-text',
on: {
click: () => {
cb();
},
},
cb()
}
}
},
this.$t('data_export.export_center'),
this.$t('data_export.export_center')
),
this.$t('data_export.export_info'),
this.$t('data_export.export_info')
]),
iconClass,
showClose: true,
customClass,
});
customClass
})
},
openMessageSuccess(text, type, cb) {
const h = this.$createElement;
const iconClass = `el-icon-${type || "success"}`;
const customClass = `de-message-${type || "success"} de-message-export`;
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, [
h("span", null, text),
message: h('p', null, [
h('span', null, text),
h(
Button,
{
props: {
type: "text",
size: "mini",
type: 'text',
size: 'mini'
},
class: "btn-text",
class: 'btn-text',
on: {
click: () => {
cb();
},
},
cb()
}
}
},
this.$t('data_export.export_center'),
),
this.$t('data_export.export_center')
)
]),
iconClass,
showClose: true,
customClass,
});
customClass
})
},
exportExcel() {
this.dialogLoading = true
@ -826,11 +838,25 @@ export default {
}
if (val && val.success === false) {
this.openMessageSuccess( `${this.chart.title ? this.chart.title : this.chart.name} 导出失败,前往`, 'error',this.exportData);
this.openMessageSuccess(`${this.chart.title ? this.chart.title : this.chart.name} 导出失败,前往`, 'error', this.exportData)
}
this.dialogLoading = false
})
},
exportSourceDetails() {
this.dialogLoading = true
this.$refs['userViewDialog'].exportSourceDetails((val) => {
if (val && val.success) {
this.openMessageLoading(this.exportData)
}
if (val && val.success === false) {
this.openMessageSuccess(`${this.chart.title ? this.chart.title : this.chart.name} 导出失败,前往`, 'error', this.exportData)
}
this.dialogLoading = false
})
},
exportViewImg() {
this.imageDownloading = true
this.$refs['userViewDialog'].exportViewImg(this.pixel, () => {

View File

@ -96,7 +96,7 @@ import ChartComponentS2 from '@/views/chart/components/ChartComponentS2'
import LabelNormalText from '@/views/chart/components/normal/LabelNormalText'
import html2canvas from 'html2canvasde'
import { hexColorToRGBA } from '@/views/chart/chart/util'
import {deepCopy, exportExcelDownload, exportImg, exportImgNew, imgUrlTrans} from '@/components/canvas/utils/utils'
import { deepCopy, exportExcelDownload, exportImg, exportImgNew, imgUrlTrans } from '@/components/canvas/utils/utils'
import { activeWatermark } from '@/components/canvas/tools/watermark'
import { proxyUserLoginInfo, userLoginInfo } from '@/api/systemInfo/userLogin'
@ -296,6 +296,10 @@ export default {
}
}
},
exportSourceDetails(callBack) {
const loadingWrapper = { val: this.linkLoading }
exportExcelDownload(this.chart, null, null, null, loadingWrapper, { downloadType: 'dataset' }, callBack)
},
exportViewImg(pixel, callback) {
this.pixel = pixel
this.exportLoading = true
@ -320,7 +324,7 @@ export default {
},
exportExcelDownload(snapshot, width, height, callBack) {
const loadingWrapper = { val: this.linkLoading }
exportExcelDownload(this.chart, snapshot, width, height, loadingWrapper, callBack)
exportExcelDownload(this.chart, snapshot, width, height, loadingWrapper, null, callBack)
},
renderComponent() {

View File

@ -468,7 +468,7 @@ export function getCacheTree(treeName) {
return JSON.parse(localStorage.getItem(treeName))
}
export function exportExcelDownload(chart, snapshot, width, height, loadingWrapper, callBack) {
export function exportExcelDownload(chart, snapshot, width, height, loadingWrapper, downloadParams, callBack) {
if (chart.render === 'antv' && !chart.data?.data?.length) {
return
}
@ -507,6 +507,7 @@ export function exportExcelDownload(chart, snapshot, width, height, loadingWrapp
const request = {
proxy: null,
viewId: chart.id,
downloadType: downloadParams?.downloadType ? downloadParams.downloadType : 'view',
viewName: excelName,
header: excelHeader,
details: excelData,

View File

@ -1128,6 +1128,7 @@ export default {
password_input_error: 'Original password input error'
},
chart: {
export_source: 'Export Source',
empty_hide: 'hide empty',
hide: 'hide',
chart_refresh_tips: 'View refresh setting takes precedence over panel refresh setting',

View File

@ -1128,6 +1128,7 @@ export default {
password_input_error: '原始密碼輸入錯誤'
},
chart: {
export_source: '導出原始明細',
empty_hide: '隱藏空值',
hide: '隱藏',
chart_refresh_tips: '視圖刷新設置優先於儀表板刷新設置',

View File

@ -1124,6 +1124,7 @@ export default {
log_live_time_error: '请填写1-4000整数'
},
chart: {
export_source: '导出原始明细',
empty_hide: '隐藏空值',
hide: '隐藏',
chart_refresh_tips: '视图刷新设置优先于仪表板刷新设置',