mirror of
https://github.com/dataease/dataease.git
synced 2025-02-24 19:42:56 +08:00
Merge pull request #11009 from dataease/pr@dev-v2@feat_app-import
feat(仪表板、大屏): 支持应用导出、应用导入相关优化
This commit is contained in:
commit
e6d8e141d6
@ -80,6 +80,7 @@ public class DatasetGroupManage {
|
||||
private Lock lock = new ReentrantLock();
|
||||
|
||||
|
||||
@Transactional
|
||||
public DatasetGroupInfoDTO save(DatasetGroupInfoDTO datasetGroupInfoDTO, boolean rename) throws Exception {
|
||||
lock.lock();
|
||||
try {
|
||||
|
@ -9,7 +9,7 @@ import java.io.Serializable;
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2024-07-16
|
||||
* @since 2024-07-17
|
||||
*/
|
||||
@TableName("visualization_template")
|
||||
public class VisualizationTemplate implements Serializable {
|
||||
|
@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
* </p>
|
||||
*
|
||||
* @author fit2cloud
|
||||
* @since 2024-07-16
|
||||
* @since 2024-07-17
|
||||
*/
|
||||
@Mapper
|
||||
public interface VisualizationTemplateMapper extends BaseMapper<VisualizationTemplate> {
|
||||
|
@ -2,8 +2,16 @@ package io.dataease.visualization.server;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.google.gson.Gson;
|
||||
import io.dataease.api.dataset.union.DatasetGroupInfoDTO;
|
||||
import io.dataease.api.visualization.request.VisualizationAppExportRequest;
|
||||
import io.dataease.api.visualization.vo.*;
|
||||
import io.dataease.dataset.dao.auto.entity.CoreDatasetGroup;
|
||||
import io.dataease.dataset.dao.auto.entity.CoreDatasetTable;
|
||||
import io.dataease.dataset.dao.auto.entity.CoreDatasetTableField;
|
||||
import io.dataease.dataset.dao.auto.mapper.CoreDatasetGroupMapper;
|
||||
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableFieldMapper;
|
||||
import io.dataease.dataset.dao.auto.mapper.CoreDatasetTableMapper;
|
||||
import io.dataease.dataset.manage.DatasetDataManage;
|
||||
import io.dataease.dataset.manage.DatasetGroupManage;
|
||||
import io.dataease.extensions.datasource.dto.DatasetTableDTO;
|
||||
@ -37,6 +45,7 @@ import io.dataease.template.dao.auto.mapper.VisualizationTemplateMapper;
|
||||
import io.dataease.template.dao.ext.ExtVisualizationTemplateMapper;
|
||||
import io.dataease.template.manage.TemplateCenterManage;
|
||||
import io.dataease.utils.*;
|
||||
import io.dataease.visualization.dao.auto.entity.CoreStore;
|
||||
import io.dataease.visualization.dao.auto.entity.DataVisualizationInfo;
|
||||
import io.dataease.visualization.dao.auto.entity.VisualizationWatermark;
|
||||
import io.dataease.visualization.dao.auto.mapper.DataVisualizationInfoMapper;
|
||||
@ -45,6 +54,7 @@ import io.dataease.visualization.dao.ext.mapper.ExtDataVisualizationMapper;
|
||||
import io.dataease.visualization.manage.CoreVisualizationManage;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -104,6 +114,15 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
@Resource
|
||||
private ExtVisualizationTemplateMapper appTemplateMapper;
|
||||
|
||||
@Resource
|
||||
private CoreDatasetGroupMapper coreDatasetGroupMapper;
|
||||
|
||||
@Resource
|
||||
private CoreDatasetTableMapper coreDatasetTableMapper;
|
||||
|
||||
@Resource
|
||||
private CoreDatasetTableFieldMapper coreDatasetTableFieldMapper;
|
||||
|
||||
@Override
|
||||
public DataVisualizationVO findCopyResource(Long dvId, String busiFlag) {
|
||||
DataVisualizationVO result = findById(new DataVisualizationBaseRequest(dvId, busiFlag));
|
||||
@ -152,7 +171,84 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
@DeLog(id = "#p0.id", pid = "#p0.pid", ot = LogOT.CREATE, stExp = "#p0.type")
|
||||
@Override
|
||||
@Transactional
|
||||
public String saveCanvas(DataVisualizationBaseRequest request) {
|
||||
public String saveCanvas(DataVisualizationBaseRequest request) throws Exception{
|
||||
Long time = System.currentTimeMillis();
|
||||
// 如果是应用 则新进行应用校验 数据集名称和 数据源名称校验
|
||||
VisualizationExport2AppVO appData = request.getAppData();
|
||||
Map<Long,Long> dsGroupIdMap = new HashMap<>();
|
||||
Map<Long,Long> dsTableIdMap = new HashMap<>();
|
||||
Map<Long,Long> dsTableFieldsIdMap = new HashMap<>();
|
||||
if(appData != null){
|
||||
try {
|
||||
Map<Long,Long> datasourceIdMap = appData.getDatasourceInfo().stream()
|
||||
.collect(Collectors.toMap(AppCoreDatasourceVO::getId, AppCoreDatasourceVO::getSystemDatasourceId));
|
||||
Long datasetFolderPid = request.getDatasetFolderPid();
|
||||
String datasetFolderName = request.getDatasetFolderName();
|
||||
QueryWrapper<CoreDatasetGroup> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("name", datasetFolderName);
|
||||
queryWrapper.eq("pid", datasetFolderPid);
|
||||
if (coreDatasetGroupMapper.exists(queryWrapper)) {
|
||||
DEException.throwException("当前数据集分组名称已存在");
|
||||
}
|
||||
//新建数据集分组
|
||||
DatasetGroupInfoDTO datasetFolderNewRequest = new DatasetGroupInfoDTO();
|
||||
datasetFolderNewRequest.setName(datasetFolderName);
|
||||
datasetFolderNewRequest.setNodeType("folder");
|
||||
datasetFolderNewRequest.setPid(datasetFolderPid);
|
||||
DatasetGroupInfoDTO datasetFolderNew = datasetGroupManage.save(datasetFolderNewRequest, false);
|
||||
Long datasetFolderNewId = datasetFolderNew.getId();
|
||||
//新建数据集
|
||||
appData.getDatasetGroupsInfo().forEach(appDatasetGroup -> {
|
||||
if ("dataset".equals(appDatasetGroup.getNodeType())) {
|
||||
Long oldId = appDatasetGroup.getId();
|
||||
Long newId = IDUtils.snowID();
|
||||
DatasetGroupInfoDTO datasetNewRequest = new DatasetGroupInfoDTO();
|
||||
BeanUtils.copyBean(datasetNewRequest, appDatasetGroup);
|
||||
datasetNewRequest.setId(newId);
|
||||
datasetNewRequest.setCreateBy(AuthUtils.getUser().getUserId() + "");
|
||||
datasetNewRequest.setUpdateBy(AuthUtils.getUser().getUserId() + "");
|
||||
datasetNewRequest.setCreateTime(time);
|
||||
datasetNewRequest.setLastUpdateTime(time);
|
||||
datasetNewRequest.setPid(datasetFolderNewId);
|
||||
try {
|
||||
datasetGroupManage.innerSave(datasetNewRequest);
|
||||
dsGroupIdMap.put(oldId,newId);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
// 新建数据集表
|
||||
appData.getDatasetTablesInfo().forEach(appCoreDatasetTableVO -> {
|
||||
Long oldId = appCoreDatasetTableVO.getId();
|
||||
Long newId = IDUtils.snowID();
|
||||
CoreDatasetTable datasetTable = new CoreDatasetTable();
|
||||
BeanUtils.copyBean(datasetTable,appCoreDatasetTableVO);
|
||||
datasetTable.setDatasetGroupId(dsGroupIdMap.get(datasetTable.getDatasetGroupId()));
|
||||
datasetTable.setId(newId);
|
||||
datasetTable.setDatasourceId(datasourceIdMap.get(datasetTable.getDatasourceId()));
|
||||
coreDatasetTableMapper.insert(datasetTable);
|
||||
dsTableIdMap.put(oldId,newId);
|
||||
|
||||
});
|
||||
// 新建数据字段
|
||||
appData.getDatasetTableFieldsInfo().forEach( appDsTableFields ->{
|
||||
Long oldId = appDsTableFields.getId();
|
||||
Long newId = IDUtils.snowID();
|
||||
CoreDatasetTableField dsDsField = new CoreDatasetTableField();
|
||||
BeanUtils.copyBean(dsDsField,appDsTableFields);
|
||||
dsDsField.setDatasetGroupId(dsGroupIdMap.get(dsDsField.getDatasetGroupId()));
|
||||
dsDsField.setDatasetTableId(dsTableIdMap.get(dsDsField.getDatasetTableId()));
|
||||
dsDsField.setDatasourceId(datasourceIdMap.get(dsDsField.getDatasourceId()));
|
||||
dsDsField.setId(newId);
|
||||
coreDatasetTableFieldMapper.insert(dsDsField);
|
||||
dsTableFieldsIdMap.put(oldId,newId);
|
||||
});
|
||||
}catch (Exception e){
|
||||
DEException.throwException("应用创建失败");
|
||||
}
|
||||
}
|
||||
DataVisualizationInfo visualizationInfo = new DataVisualizationInfo();
|
||||
BeanUtils.copyBean(visualizationInfo, request);
|
||||
visualizationInfo.setNodeType(request.getNodeType() == null ? DataVisualizationConstants.NODE_TYPE.LEAF : request.getNodeType());
|
||||
@ -168,6 +264,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
}
|
||||
Long newDvId = coreVisualizationManage.innerSave(visualizationInfo);
|
||||
request.setId(newDvId);
|
||||
// TODO 还原ID信息
|
||||
//保存图表信息
|
||||
chartDataManage.saveChartViewFromVisualization(request.getComponentData(), newDvId, request.getCanvasViewInfo());
|
||||
return newDvId.toString();
|
||||
@ -378,6 +475,11 @@ public class DataVisualizationServer implements DataVisualizationApi {
|
||||
VisualizationTemplateExtendDataDTO extendDataDTO = new VisualizationTemplateExtendDataDTO(newDvId, newViewId, originViewData);
|
||||
extendDataInfo.put(newViewId, extendDataDTO);
|
||||
templateData = templateData.replaceAll(originViewId, newViewId.toString());
|
||||
if(appData != null){
|
||||
Map appDataFormat = JsonUtil.parse(appData,Map.class);
|
||||
String sourceDvId = (String) appDataFormat.get("id");
|
||||
appData = appData.replaceAll(originViewId, newViewId.toString()).replaceAll(sourceDvId, newDvId.toString());
|
||||
}
|
||||
canvasViewInfo.put(chartView.getId(), chartView);
|
||||
//插入模板数据 此处预先插入减少数据交互量
|
||||
VisualizationTemplateExtendData extendData = new VisualizationTemplateExtendData();
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus-secondary'
|
||||
import eventBus from '@/utils/eventBus'
|
||||
import { ref, nextTick, computed } from 'vue'
|
||||
import { ref, nextTick, computed, toRefs } from 'vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
@ -32,6 +32,7 @@ const dvMainStore = dvMainStoreWithOut()
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
const { styleChangeTimes, snapshotIndex } = storeToRefs(snapshotStore)
|
||||
const resourceGroupOpt = ref(null)
|
||||
const resourceAppOpt = ref(null)
|
||||
const dvToolbarMain = ref(null)
|
||||
const { componentData, canvasStyleData, canvasViewInfo, dvInfo, editMode } =
|
||||
storeToRefs(dvMainStore)
|
||||
@ -41,6 +42,15 @@ const dvModel = 'dataV'
|
||||
const outerParamsSetRef = ref(null)
|
||||
const fullScreeRef = ref(null)
|
||||
|
||||
const props = defineProps({
|
||||
createType: {
|
||||
type: String,
|
||||
default: 'create'
|
||||
}
|
||||
})
|
||||
|
||||
const { createType } = toRefs(props)
|
||||
|
||||
const closeEditCanvasName = () => {
|
||||
nameEdit.value = false
|
||||
if (!inputName.value || !inputName.value.trim()) {
|
||||
@ -89,11 +99,33 @@ const resourceOptFinish = param => {
|
||||
saveCanvasWithCheck()
|
||||
}
|
||||
}
|
||||
const appOptFinish = param => {
|
||||
if (param && param.opt === 'newLeaf') {
|
||||
dvInfo.value.dataState = 'ready'
|
||||
dvInfo.value.pid = param.pid
|
||||
dvInfo.value.name = param.name
|
||||
}
|
||||
}
|
||||
|
||||
const saveCanvasWithCheck = () => {
|
||||
const appData = dvMainStore.getAppDataInfo()
|
||||
if (dvInfo.value.dataState === 'prepare') {
|
||||
const params = { name: dvInfo.value.name, leaf: true, id: dvInfo.value.pid }
|
||||
resourceGroupOpt.value.optInit('leaf', params, 'newLeaf', true)
|
||||
if (appData) {
|
||||
// 应用保存
|
||||
const params = {
|
||||
base: {
|
||||
pid: '',
|
||||
name: dvInfo.value.name,
|
||||
datasetFolderPid: null,
|
||||
datasetFolderName: dvInfo.value.name
|
||||
},
|
||||
appData: appData
|
||||
}
|
||||
resourceAppOpt.value.init(params)
|
||||
} else {
|
||||
const params = { name: dvInfo.value.name, leaf: true, id: dvInfo.value.pid }
|
||||
resourceGroupOpt.value.optInit('leaf', params, 'newLeaf', true)
|
||||
}
|
||||
return
|
||||
}
|
||||
saveResource()
|
||||
@ -345,10 +377,12 @@ const fullScreenPreview = () => {
|
||||
ref="resourceGroupOpt"
|
||||
/>
|
||||
<de-app-apply
|
||||
ref="resourceGroupOpt"
|
||||
ref="resourceAppOpt"
|
||||
:component-data="componentData"
|
||||
:dv-info="dvInfo"
|
||||
:canvas-view-info="canvasViewInfo"
|
||||
cur-canvas-type="dataV"
|
||||
@saveApp="appOptFinish"
|
||||
></de-app-apply>
|
||||
</div>
|
||||
<de-fullscreen ref="fullScreeRef" show-position="dvEdit"></de-fullscreen>
|
||||
|
@ -45,6 +45,7 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
inMobile: false,
|
||||
firstLoadMap: [],
|
||||
canvasStyleData: { ...deepCopy(DEFAULT_CANVAS_STYLE_DATA_DARK), backgroundColor: null },
|
||||
appData: {}, //应用信息
|
||||
// 当前展示画布缓存数据
|
||||
componentDataCache: null,
|
||||
// PC布局画布组件数据
|
||||
@ -245,7 +246,12 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
setCanvasViewInfo(canvasViewInfo) {
|
||||
this.canvasViewInfo = canvasViewInfo
|
||||
},
|
||||
|
||||
getAppDataInfo() {
|
||||
return this.appData
|
||||
},
|
||||
setAppDataInfo(appDataInfo) {
|
||||
this.appData = appDataInfo
|
||||
},
|
||||
setCurComponent({ component, index }) {
|
||||
if (!component && this.curComponent) {
|
||||
this.curComponent['editing'] = false
|
||||
@ -1205,13 +1211,14 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
this.canvasState[key] = value
|
||||
}
|
||||
},
|
||||
createInit(dvType, resourceId?, pid?, watermarkInfo?) {
|
||||
createInit(dvType, resourceId?, pid?, watermarkInfo?, preName) {
|
||||
const optName = dvType === 'dashboard' ? '新建仪表板' : '新建数据大屏'
|
||||
const name = preName ? preName : optName
|
||||
this.dvInfo = {
|
||||
dataState: 'prepare',
|
||||
optType: null,
|
||||
id: resourceId,
|
||||
name: optName,
|
||||
name: name,
|
||||
pid: pid,
|
||||
type: dvType,
|
||||
status: 1,
|
||||
|
@ -25,7 +25,7 @@ import {
|
||||
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { curBatchOptComponents, dvInfo, canvasStyleData, componentData, canvasViewInfo } =
|
||||
const { curBatchOptComponents, dvInfo, canvasStyleData, componentData, canvasViewInfo, appData } =
|
||||
storeToRefs(dvMainStore)
|
||||
const snapshotStore = snapshotStoreWithOut()
|
||||
|
||||
@ -349,6 +349,7 @@ export async function canvasSave(callBack) {
|
||||
canvasStyleData: JSON.stringify(canvasStyleData.value),
|
||||
componentData: JSON.stringify(componentDataToSave),
|
||||
canvasViewInfo: canvasViewInfo.value,
|
||||
appData: appData.value,
|
||||
...dvInfo.value,
|
||||
watermarkInfo: null
|
||||
}
|
||||
@ -521,6 +522,10 @@ export async function decompressionPre(params, callBack) {
|
||||
.then(response => {
|
||||
const deTemplateDataTemp = response.data
|
||||
const sourceComponentData = JSON.parse(deTemplateDataTemp['componentData'])
|
||||
let appData
|
||||
if (deTemplateDataTemp['appData']) {
|
||||
appData = JSON.parse(deTemplateDataTemp['appData'])
|
||||
}
|
||||
sourceComponentData.forEach(componentItem => {
|
||||
// 2 为基础版本 此处需要增加仪表板矩阵密度
|
||||
if (
|
||||
@ -538,7 +543,10 @@ export async function decompressionPre(params, callBack) {
|
||||
canvasStyleData: sourceCanvasStyle,
|
||||
componentData: sourceComponentData,
|
||||
canvasViewInfo: deTemplateDataTemp['canvasViewInfo'],
|
||||
appData: deTemplateDataTemp['appData']
|
||||
appData: appData,
|
||||
baseInfo: {
|
||||
preName: deTemplateDataTemp.name
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
|
@ -5,8 +5,9 @@ import { Plus, Search } from '@element-plus/icons-vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import _ from 'lodash'
|
||||
import { getDatasetTree } from '@/api/dataset'
|
||||
import { getDatasetTree, getDatasourceList } from '@/api/dataset'
|
||||
import { ElFormItem, FormInstance } from 'element-plus-secondary'
|
||||
import type { DataSource } from '@/views/visualized/data/dataset/form/util'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@ -14,10 +15,12 @@ const props = withDefaults(
|
||||
modelValue?: string | number
|
||||
stateObj: any
|
||||
viewId: string
|
||||
sourceType: string
|
||||
}>(),
|
||||
{
|
||||
datasetTree: () => [],
|
||||
themes: 'dark'
|
||||
themes: 'dark',
|
||||
sourceType: 'dataset'
|
||||
}
|
||||
)
|
||||
|
||||
@ -29,9 +32,13 @@ const datasetTree = ref<Tree[]>([])
|
||||
const toolTip = computed(() => {
|
||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
||||
})
|
||||
|
||||
const sourceName = computed(() => (props.sourceType === 'datasource' ? '数据源' : '数据集'))
|
||||
|
||||
const initDataset = () => {
|
||||
loadingDatasetTree.value = true
|
||||
getDatasetTree({})
|
||||
const method = props.sourceType === 'datasource' ? getDatasourceList : getDatasetTree
|
||||
method({})
|
||||
.then(res => {
|
||||
datasetTree.value = (res as unknown as Tree[]) || []
|
||||
})
|
||||
@ -110,7 +117,7 @@ const exist = computed(() => {
|
||||
|
||||
const selectedNodeName = computed(() => {
|
||||
if (!exist.value) {
|
||||
return '数据集不存在'
|
||||
return sourceName.value + '不存在'
|
||||
}
|
||||
return selectedNode.value?.name
|
||||
})
|
||||
@ -212,7 +219,7 @@ onMounted(() => {
|
||||
v-model="selectedNodeName"
|
||||
readonly
|
||||
class="data-set-dark"
|
||||
placeholder="请选择数据集"
|
||||
:placeholder="'请选择' + sourceName"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="input-arrow-icon" :class="{ reverse: _popoverShow }">
|
||||
@ -227,7 +234,7 @@ onMounted(() => {
|
||||
<el-container :class="themes">
|
||||
<el-header>
|
||||
<div class="m-title" :class="{ dark: themes === 'dark' }">
|
||||
<div>{{ t('dataset.datalist') }}</div>
|
||||
<div>{{ sourceName }}</div>
|
||||
<el-button type="primary" link class="refresh-btn" @click="refresh">
|
||||
{{ t('commons.refresh') }}
|
||||
</el-button>
|
||||
@ -244,7 +251,7 @@ onMounted(() => {
|
||||
<el-main :class="{ dark: themes === 'dark' }">
|
||||
<el-scrollbar max-height="252px" always>
|
||||
<div class="m-loading" v-if="loadingDatasetTree" v-loading="loadingDatasetTree"></div>
|
||||
<div class="empty-info" v-if="showEmptyInfo">暂无数据集</div>
|
||||
<div class="empty-info" v-if="showEmptyInfo">暂无{{ sourceName }}</div>
|
||||
<!-- <div class="empty-info" v-if="showEmptySearchInfo">暂无相关数据</div>-->
|
||||
<el-tree
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@ -294,7 +301,7 @@ onMounted(() => {
|
||||
<el-footer v-if="!isDataEaseBi">
|
||||
<div class="footer-container">
|
||||
<el-button type="primary" :icon="Plus" link class="add-btn" @click="addDataset">
|
||||
新建数据集
|
||||
新建{{ sourceName }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-footer>
|
||||
|
@ -3,7 +3,7 @@
|
||||
:title="'保存应用'"
|
||||
v-model="state.appApplyDrawer"
|
||||
custom-class="de-user-drawer"
|
||||
size="600px"
|
||||
size="500px"
|
||||
direction="rtl"
|
||||
>
|
||||
<div class="app-export">
|
||||
@ -12,16 +12,17 @@
|
||||
:model="state.form"
|
||||
:rules="state.rule"
|
||||
class="de-form-item"
|
||||
size="middle"
|
||||
label-width="180px"
|
||||
label-position="top"
|
||||
>
|
||||
<div class="de-row-rules" style="margin: 0 0 16px">
|
||||
<span>基本信息</span>
|
||||
</div>
|
||||
<el-form-item :label="dvPreName + '名称'" prop="appName">
|
||||
<el-form-item :label="dvPreName + '名称'" prop="name">
|
||||
<el-input v-model="state.form.name" autocomplete="off" :placeholder="'请输入名称'" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="dvPreName + '所在位置'" prop="version">
|
||||
<el-form-item :label="dvPreName + '所在位置'" prop="pid">
|
||||
<el-tree-select
|
||||
style="width: 100%"
|
||||
@keydown.stop
|
||||
@ -44,23 +45,23 @@
|
||||
</template>
|
||||
</el-tree-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="'数据集分组名称'" prop="appName">
|
||||
<el-form-item :label="'数据集分组名称'" prop="datasetFolderName">
|
||||
<el-input
|
||||
v-model="state.form.datasetFolderName"
|
||||
autocomplete="off"
|
||||
:placeholder="'请输入名称'"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据集分组位置" prop="version">
|
||||
<el-form-item label="数据集分组位置" prop="datasetFolderPid">
|
||||
<el-tree-select
|
||||
style="width: 100%"
|
||||
@keydown.stop
|
||||
@keyup.stop
|
||||
v-model="state.form.datasetFolderPid"
|
||||
:data="state.dvTree"
|
||||
:data="state.dsTree"
|
||||
:props="state.propsTree"
|
||||
@node-click="dvTreeSelect"
|
||||
:filter-method="dvTreeFilterMethod"
|
||||
@node-click="dsTreeSelect"
|
||||
:filter-method="dsTreeFilterMethod"
|
||||
:render-after-expand="false"
|
||||
filterable
|
||||
>
|
||||
@ -77,13 +78,47 @@
|
||||
<div class="de-row-rules" style="margin: 0 0 16px">
|
||||
<span>数据源信息</span>
|
||||
</div>
|
||||
<div>数据源信息配置</div>
|
||||
<el-row class="datasource-link">
|
||||
<el-row class="head">
|
||||
<el-col :span="11">应用数据源</el-col><el-col :span="2"></el-col
|
||||
><el-col :span="11">系统数据源</el-col>
|
||||
</el-row>
|
||||
<el-row
|
||||
:key="index"
|
||||
class="content"
|
||||
v-for="(appDatasource, index) in state.appData.datasourceInfo"
|
||||
>
|
||||
<el-col :span="11">
|
||||
<el-select style="width: 100%" v-model="appDatasource.name" disabled>
|
||||
<el-option
|
||||
:key="appDatasource.name"
|
||||
:label="appDatasource.name"
|
||||
:value="appDatasource.name"
|
||||
>
|
||||
</el-option>
|
||||
</el-select> </el-col
|
||||
><el-col :span="2" class="icon-center">
|
||||
<Icon style="width: 20px; height: 20px" name="dv-link-target" /></el-col
|
||||
><el-col :span="11">
|
||||
<dataset-select
|
||||
ref="datasetSelector"
|
||||
v-model="appDatasource.systemDatasourceId"
|
||||
style="flex: 1"
|
||||
:state-obj="state"
|
||||
themes="light"
|
||||
source-type="datasource"
|
||||
@add-ds-window="addDsWindow"
|
||||
view-id="0"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="apply" style="width: 100%">
|
||||
<el-button secondary @click="close">{{ $t('commons.cancel') }} </el-button>
|
||||
<el-button type="primary" @click="downloadApp">保存</el-button>
|
||||
<el-button type="primary" @click="saveApp">保存</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
@ -98,11 +133,20 @@ import {
|
||||
ElInput,
|
||||
ElTreeSelect
|
||||
} from 'element-plus-secondary'
|
||||
import { computed, reactive, ref, toRefs } from 'vue'
|
||||
import { computed, PropType, reactive, ref, toRefs } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { queryTreeApi } from '@/api/visualization/dataVisualization'
|
||||
import { BusiTreeNode, BusiTreeRequest } from '@/models/tree/TreeNode'
|
||||
import { getDatasetTree } from '@/api/dataset'
|
||||
import DatasetSelect from '@/views/chart/components/editor/dataset-select/DatasetSelect.vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
const { t } = useI18n()
|
||||
const emits = defineEmits(['closeDraw', 'downLoadApp'])
|
||||
const emits = defineEmits(['closeDraw', 'saveApp'])
|
||||
const appSaveForm = ref(null)
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { dvInfo, appData } = storeToRefs(dvMainStore)
|
||||
|
||||
const props = defineProps({
|
||||
componentData: {
|
||||
@ -113,34 +157,42 @@ const props = defineProps({
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
dvInfo: {
|
||||
type: Object,
|
||||
curCanvasType: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
dvType: {
|
||||
type: String,
|
||||
default: 'dashboard'
|
||||
themes: {
|
||||
type: String as PropType<EditorTheme>,
|
||||
default: 'dark'
|
||||
}
|
||||
})
|
||||
|
||||
const { componentData, canvasViewInfo, dvInfo, dvType } = toRefs(props)
|
||||
const { componentData, canvasViewInfo, curCanvasType, themes } = toRefs(props)
|
||||
|
||||
const dvPreName = computed(() => (dvType.value === 'dashboard' ? '仪表板' : '数据大屏'))
|
||||
const dvPreName = computed(() => (curCanvasType.value === 'dashboard' ? '仪表板' : '数据大屏'))
|
||||
const addDsWindow = () => {
|
||||
// do addDsWindow
|
||||
const url = '#/data/datasource?opt=create'
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
const state = reactive({
|
||||
appApplyDrawer: false,
|
||||
dvTree: [],
|
||||
dsTree: [],
|
||||
propsTree: {
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
isLeaf: node => !node.children?.length
|
||||
},
|
||||
appData: {
|
||||
datasourceInfo: []
|
||||
},
|
||||
form: {
|
||||
pid: '',
|
||||
name: '新建',
|
||||
datasetFolderPid: null,
|
||||
datasetFolderName: null,
|
||||
datasourceMap: {} // 数据源ID映射
|
||||
datasetFolderName: null
|
||||
},
|
||||
rule: {
|
||||
name: [
|
||||
@ -173,8 +225,6 @@ const state = reactive({
|
||||
datasetFolderPid: [
|
||||
{
|
||||
required: true,
|
||||
min: 2,
|
||||
max: 25,
|
||||
message: '请选择数据集分组所属文件夹',
|
||||
trigger: 'blur'
|
||||
}
|
||||
@ -182,20 +232,59 @@ const state = reactive({
|
||||
}
|
||||
})
|
||||
|
||||
const initData = () => {
|
||||
const request = { busiFlag: curCanvasType.value, leaf: false, weight: 7 }
|
||||
queryTreeApi(request).then(res => {
|
||||
const resultTree = res || []
|
||||
dfs(resultTree as unknown as BusiTreeNode[])
|
||||
state.dvTree = (resultTree as unknown as BusiTreeNode[]) || []
|
||||
if (state.dvTree.length && state.dvTree[0].name === 'root' && state.dvTree[0].id === '0') {
|
||||
state.dvTree[0].name = curCanvasType.value === 'dataV' ? '数据大屏' : '仪表板'
|
||||
}
|
||||
})
|
||||
|
||||
const requestDs = { leaf: false, weight: 7 } as BusiTreeRequest
|
||||
getDatasetTree(requestDs).then(res => {
|
||||
dfs(res as unknown as BusiTreeNode[])
|
||||
state.dsTree = (res as unknown as BusiTreeNode[]) || []
|
||||
if (state.dsTree.length && state.dsTree[0].name === 'root' && state.dsTree[0].id === '0') {
|
||||
state.dsTree[0].name = '数据集'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const dfs = (arr: BusiTreeNode[]) => {
|
||||
arr.forEach(ele => {
|
||||
ele['value'] = ele.id
|
||||
if (ele.children?.length) {
|
||||
dfs(ele.children)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const init = params => {
|
||||
console.log('init==')
|
||||
state.appApplyDrawer = true
|
||||
state.form = params
|
||||
state.form = params.base
|
||||
state.appData.datasourceInfo = deepCopy(appData.value?.datasourceInfo)
|
||||
initData()
|
||||
}
|
||||
|
||||
const dvTreeFilterMethod = value => {
|
||||
state.dvTree = [...state.dvTree].filter(item => item.name.includes(value))
|
||||
}
|
||||
|
||||
const dsTreeFilterMethod = value => {
|
||||
state.dsTree = [...state.dsTree].filter(item => item.name.includes(value))
|
||||
}
|
||||
|
||||
const dvTreeSelect = element => {
|
||||
state.form.pid = element.id
|
||||
}
|
||||
|
||||
const dsTreeSelect = element => {
|
||||
state.form.datasetFolderPid = element.id
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
emits('closeDraw')
|
||||
state.appApplyDrawer = false
|
||||
@ -204,8 +293,14 @@ const close = () => {
|
||||
const saveApp = () => {
|
||||
appSaveForm.value?.validate(valid => {
|
||||
if (valid) {
|
||||
const viewIds = []
|
||||
const dsIds = []
|
||||
// 还原datasource
|
||||
appData.value['datasourceInfo'] = state.appData.datasourceInfo
|
||||
dvInfo.value['pid'] = state.form.pid
|
||||
dvInfo.value['name'] = state.form.name
|
||||
dvInfo.value['datasetFolderPid'] = state.form.datasetFolderPid
|
||||
dvInfo.value['datasetFolderName'] = state.form.datasetFolderName
|
||||
dvInfo.value['dataState'] = 'ready'
|
||||
emits('saveApp')
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
@ -241,6 +336,7 @@ defineExpose({
|
||||
line-height: 22px;
|
||||
padding-left: 10px;
|
||||
margin: 24px 0 16px 0;
|
||||
color: var(--ed-text-color-regular);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
@ -253,4 +349,37 @@ defineExpose({
|
||||
background: #3370ff;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
margin-left: 8.75px;
|
||||
width: 120px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.datasource-link {
|
||||
color: var(--ed-text-color-regular);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
.head {
|
||||
width: 100%;
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-center {
|
||||
padding: 0 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
@ -326,13 +326,15 @@ onMounted(async () => {
|
||||
console.error('can not find watermark info')
|
||||
}
|
||||
let deTemplateData
|
||||
let preName
|
||||
if (createType === 'template') {
|
||||
const templateParamsApply = JSON.parse(Base64.decode(decodeURIComponent(templateParams + '')))
|
||||
await decompressionPre(templateParamsApply, result => {
|
||||
deTemplateData = result
|
||||
preName = deTemplateData.baseInfo?.preName
|
||||
})
|
||||
}
|
||||
dvMainStore.createInit('dataV', null, pid, watermarkBaseInfo)
|
||||
dvMainStore.createInit('dataV', null, pid, watermarkBaseInfo, preName)
|
||||
nextTick(() => {
|
||||
state.canvasInitStatus = true
|
||||
dvMainStore.setDataPrepareState(true)
|
||||
@ -342,6 +344,7 @@ onMounted(async () => {
|
||||
dvMainStore.setComponentData(deTemplateData['componentData'])
|
||||
dvMainStore.setCanvasStyle(deTemplateData['canvasStyleData'])
|
||||
dvMainStore.setCanvasViewInfo(deTemplateData['canvasViewInfo'])
|
||||
dvMainStore.setAppDataInfo(deTemplateData['appData'])
|
||||
setTimeout(() => {
|
||||
snapshotStore.recordSnapshotCache()
|
||||
}, 1500)
|
||||
|
@ -46,7 +46,7 @@ public interface DataVisualizationApi {
|
||||
@PostMapping("/saveCanvas")
|
||||
@DePermit(value = {"#p0.pid + ':manage'"}, busiFlag = "#p0.type")
|
||||
@Operation(summary = "画布保存")
|
||||
String saveCanvas(@RequestBody DataVisualizationBaseRequest request);
|
||||
String saveCanvas(@RequestBody DataVisualizationBaseRequest request) throws Exception;
|
||||
|
||||
@PostMapping("/updateCanvas")
|
||||
@DePermit(value = {"#p0.id + ':manage'"}, busiFlag = "#p0.type")
|
||||
|
@ -1,6 +1,9 @@
|
||||
package io.dataease.api.visualization.request;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.dataease.api.visualization.vo.DataVisualizationVO;
|
||||
import io.dataease.api.visualization.vo.VisualizationExport2AppVO;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@ -32,11 +35,22 @@ public class DataVisualizationBaseRequest extends DataVisualizationVO {
|
||||
private String source;
|
||||
|
||||
// 定时报告id
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long reportId;
|
||||
|
||||
// 定时报告任务id
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long taskId;
|
||||
|
||||
private VisualizationExport2AppVO appData;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
// 数据集分组PID
|
||||
private Long datasetFolderPid;
|
||||
|
||||
// 数据集分组名称
|
||||
private String datasetFolderName;
|
||||
|
||||
|
||||
public DataVisualizationBaseRequest(Long id,String busiFlag) {
|
||||
this.busiFlag = busiFlag;
|
||||
|
@ -79,4 +79,9 @@ public class AppCoreDatasourceVO implements Serializable {
|
||||
*/
|
||||
private String taskStatus;
|
||||
|
||||
/**
|
||||
* 映射系统数据源ID
|
||||
*/
|
||||
private Long systemDatasourceId;
|
||||
|
||||
}
|
||||
|
@ -17,27 +17,27 @@ public class VisualizationExport2AppVO {
|
||||
|
||||
private String visualizationViewsInfo;
|
||||
|
||||
private String chartViewsInfo;
|
||||
List<AppCoreChartViewVO> chartViewsInfo;
|
||||
|
||||
private String datasetGroupsInfo;
|
||||
List<AppCoreDatasetGroupVO> datasetGroupsInfo;
|
||||
|
||||
private String datasetTablesInfo;
|
||||
List<AppCoreDatasetTableVO> datasetTablesInfo;
|
||||
|
||||
private String datasetTableFieldsInfo;
|
||||
List<AppCoreDatasetTableFieldVO> datasetTableFieldsInfo;
|
||||
|
||||
private String datasourceInfo;
|
||||
List<AppCoreDatasourceVO> datasourceInfo;
|
||||
|
||||
private String datasourceTaskInfo;
|
||||
List<AppCoreDatasourceTaskVO> datasourceTaskInfo;
|
||||
|
||||
private String linkJumps;
|
||||
List<VisualizationLinkJumpVO> linkJumps;
|
||||
|
||||
private String linkJumpInfos;
|
||||
List<VisualizationLinkJumpInfoVO> linkJumpInfos;
|
||||
|
||||
private String linkJumpTargetInfos;
|
||||
List<VisualizationLinkJumpTargetViewInfoVO> linkJumpTargetInfos;
|
||||
|
||||
private String linkages;
|
||||
List<VisualizationLinkageVO> linkages;
|
||||
|
||||
private String linkageFields;
|
||||
List<VisualizationLinkageFieldVO> linkageFields;
|
||||
|
||||
public VisualizationExport2AppVO() {
|
||||
|
||||
@ -58,20 +58,18 @@ public class VisualizationExport2AppVO {
|
||||
List<VisualizationLinkJumpTargetViewInfoVO> linkJumpTargetViewVOInfo,
|
||||
List<VisualizationLinkageVO> linkagesVOInfo,
|
||||
List<VisualizationLinkageFieldVO> linkageFieldVOInfo) {
|
||||
List<Object> empty = new ArrayList<>();
|
||||
Gson gson = new Gson();
|
||||
this.checkStatus = true;
|
||||
this.checkMes = "success";
|
||||
this.chartViewsInfo = gson.toJson(chartViewVOInfo != null ? chartViewVOInfo : empty);
|
||||
this.datasetGroupsInfo = gson.toJson(datasetGroupVOInfo != null ? datasetGroupVOInfo : empty);
|
||||
this.datasetTablesInfo = gson.toJson(datasetTableVOInfo != null ? datasetTableVOInfo : empty);
|
||||
this.datasetTableFieldsInfo = gson.toJson(datasetTableFieldVOInfo != null ? datasetTableFieldVOInfo : empty);
|
||||
this.datasourceTaskInfo = gson.toJson(datasourceTaskVOInfo != null ? datasourceTaskVOInfo : empty);
|
||||
this.datasourceInfo = gson.toJson(datasourceVOInfo != null ? datasourceVOInfo : empty);
|
||||
this.linkJumps = gson.toJson(linkJumpVOInfo != null ? linkJumpVOInfo : empty);
|
||||
this.linkJumpInfos = gson.toJson(linkJumpInfoVOInfo != null ? linkJumpInfoVOInfo : empty);
|
||||
this.linkJumpTargetInfos = gson.toJson(linkJumpTargetViewVOInfo != null ? linkJumpTargetViewVOInfo : empty);
|
||||
this.linkages = gson.toJson(linkagesVOInfo != null ? linkagesVOInfo : empty);
|
||||
this.linkageFields = gson.toJson(linkageFieldVOInfo != null ? linkageFieldVOInfo : empty);
|
||||
this.chartViewsInfo = chartViewVOInfo != null ? chartViewVOInfo : new ArrayList<>();
|
||||
this.datasetGroupsInfo = datasetGroupVOInfo != null ? datasetGroupVOInfo : new ArrayList<>();
|
||||
this.datasetTablesInfo = datasetTableVOInfo != null ? datasetTableVOInfo : new ArrayList<>();
|
||||
this.datasetTableFieldsInfo = datasetTableFieldVOInfo != null ? datasetTableFieldVOInfo : new ArrayList<>();
|
||||
this.datasourceTaskInfo = datasourceTaskVOInfo != null ? datasourceTaskVOInfo : new ArrayList<>();
|
||||
this.datasourceInfo = datasourceVOInfo != null ? datasourceVOInfo : new ArrayList<>();
|
||||
this.linkJumps = linkJumpVOInfo != null ? linkJumpVOInfo : new ArrayList<>();
|
||||
this.linkJumpInfos = linkJumpInfoVOInfo != null ? linkJumpInfoVOInfo : new ArrayList<>();
|
||||
this.linkJumpTargetInfos = linkJumpTargetViewVOInfo != null ? linkJumpTargetViewVOInfo : new ArrayList<>();
|
||||
this.linkages = linkagesVOInfo != null ? linkagesVOInfo : new ArrayList<>();
|
||||
this.linkageFields = linkageFieldVOInfo != null ? linkageFieldVOInfo : new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user