Merge pull request #10988 from dataease/pr@dev-v2@feat_app-download

feat(仪表板、大屏): 支持应用导出
This commit is contained in:
王嘉豪 2024-07-16 17:48:03 +08:00 committed by GitHub
commit 9d3c055ca0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 429 additions and 55 deletions

View File

@ -21,11 +21,11 @@ public class MybatisPlusGenerator {
/**
* 业务模块例如datasource,dataset,panel等
*/
private static final String busi = "visualization";
private static final String busi = "template";
/**
* 这是要生成代码的表名称
*/
private static final String TABLE_NAME = "visualization_report_filter";
private static final String TABLE_NAME = "visualization_template";
/**
* 下面两个配置基本上不用动

View File

@ -5,11 +5,11 @@ import java.io.Serializable;
/**
* <p>
*
* 模板表
* </p>
*
* @author fit2cloud
* @since 2024-04-11
* @since 2024-07-16
*/
@TableName("visualization_template")
public class VisualizationTemplate implements Serializable {
@ -37,12 +37,12 @@ public class VisualizationTemplate implements Serializable {
private Integer level;
/**
* 种类 dataV or dashboard 目录或者文件夹
* 种类 dataV or dashboard 目录或者文件夹
*/
private String dvType;
/**
* 节点类型 folder or panel 目录或者文件夹
* 节点类型 app or template 应用 或者 模板
*/
private String nodeType;
@ -62,7 +62,7 @@ public class VisualizationTemplate implements Serializable {
private String snapshot;
/**
* 类型 system 系统内置 self 用户自建
* 类型 system 系统内置 self 用户自建
*/
private String templateType;
@ -81,14 +81,16 @@ public class VisualizationTemplate implements Serializable {
*/
private String dynamicData;
/**
* app数据
*/
private String appData;
/**
* 使用次数
*/
private Integer useCount;
/**
* 使用仪表板的版本
*/
private Integer version;
public String getId() {
@ -195,6 +197,14 @@ public class VisualizationTemplate implements Serializable {
this.dynamicData = dynamicData;
}
public String getAppData() {
return appData;
}
public void setAppData(String appData) {
this.appData = appData;
}
public Integer getUseCount() {
return useCount;
}
@ -227,6 +237,7 @@ public class VisualizationTemplate implements Serializable {
", templateStyle = " + templateStyle +
", templateData = " + templateData +
", dynamicData = " + dynamicData +
", appData = " + appData +
", useCount = " + useCount +
", version = " + version +
"}";

View File

@ -6,11 +6,11 @@ import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* 模板表 Mapper 接口
* </p>
*
* @author fit2cloud
* @since 2024-04-11
* @since 2024-07-16
*/
@Mapper
public interface VisualizationTemplateMapper extends BaseMapper<VisualizationTemplate> {

View File

@ -52,6 +52,6 @@ public interface ExtVisualizationTemplateMapper{
List<VisualizationLinkJumpInfoVO> findAppLinkJumpInfoInfo(@Param("dvId") Long dvId);
List<VisualizationLinkJumpTargetViewInfoVO> findAppJumpTargetViewInfo(@Param("dvId") Long dvId);
List<VisualizationLinkJumpTargetViewInfoVO> findAppLinkJumpTargetViewInfoInfo(@Param("dvId") Long dvId);
}

View File

@ -80,10 +80,10 @@ public class TemplateManageService implements TemplateManageApi {
request.setId(UUID.randomUUID().toString());
request.setCreateTime(System.currentTimeMillis());
request.setCreateBy(AuthUtils.getUser().getUserId().toString());
if ("template".equals(request.getNodeType())) {
if ("template".equals(request.getNodeType()) || "app".equals(request.getNodeType())) {
//Store static resource into the server
staticResourceServer.saveFilesToServe(request.getStaticResource());
String snapshotName = "template-" + request.getId() + ".jpeg";
String snapshotName = request.getNodeType() + "-" + request.getId() + ".jpeg";
staticResourceServer.saveSingleFileToServe(snapshotName, request.getSnapshot().replace("data:image/jpeg;base64,", ""));
request.setSnapshot("/" + UPLOAD_URL_PREFIX + '/' + snapshotName);
}
@ -107,7 +107,7 @@ public class TemplateManageService implements TemplateManageApi {
VisualizationTemplate template = new VisualizationTemplate();
BeanUtils.copyBean(template, request);
if(template.getVersion() == null){
if (template.getVersion() == null) {
template.setVersion(2);
}
templateMapper.insert(template);
@ -137,7 +137,7 @@ public class TemplateManageService implements TemplateManageApi {
}
VisualizationTemplate template = new VisualizationTemplate();
BeanUtils.copyBean(template, request);
if(template.getVersion() == null){
if (template.getVersion() == null) {
template.setVersion(2);
}
templateMapper.updateById(template);
@ -191,7 +191,7 @@ public class TemplateManageService implements TemplateManageApi {
@Override
public String checkCategoryTemplateBatchNames(TemplateManageRequest request) {
Long result = extTemplateMapper.checkCategoryTemplateBatchNames(request.getTemplateNames(),request.getCategories(),request.getTemplateArray());
Long result = extTemplateMapper.checkCategoryTemplateBatchNames(request.getTemplateNames(), request.getCategories(), request.getTemplateArray());
if (result == 0) {
return CommonConstants.CHECK_RESULT.NONE;
} else {
@ -272,7 +272,7 @@ public class TemplateManageService implements TemplateManageApi {
public List<String> findCategoriesByTemplateIds(TemplateManageRequest request) throws Exception {
if (!CollectionUtils.isEmpty(request.getTemplateArray())) {
List<String> result = extTemplateMapper.findTemplateArrayCategories(request.getTemplateArray());
if(!CollectionUtils.isEmpty(result) &&result.size() == 1 ){
if (!CollectionUtils.isEmpty(result) && result.size() == 1) {
return Arrays.stream(result.get(0).split(",")).toList();
}
}

View File

@ -304,6 +304,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
String templateData = null;
String dynamicData = null;
String staticResource = null;
String appData = null;
String name = null;
String dvType = null;
Integer version = null;
@ -316,6 +317,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
name = visualizationTemplate.getName();
dvType = visualizationTemplate.getDvType();
version = visualizationTemplate.getVersion();
appData = visualizationTemplate.getAppData();
// 模板市场记录
coreOptRecentManage.saveOpt(request.getTemplateId(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE, OptConstants.OPT_TYPE.NEW);
VisualizationTemplate visualizationTemplateUpdate = new VisualizationTemplate();
@ -327,6 +329,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
templateData = request.getComponentData();
dynamicData = request.getDynamicData();
staticResource = request.getStaticResource();
appData = request.getAppData();
name = request.getName();
dvType = request.getType();
} else if (DataVisualizationConstants.NEW_PANEL_FROM.NEW_MARKET_TEMPLATE.equals(newFrom)) {
@ -341,6 +344,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
name = templateFileInfo.getName();
dvType = templateFileInfo.getDvType();
version = templateFileInfo.getVersion();
appData = templateFileInfo.getAppData();
// 模板市场记录
coreOptRecentManage.saveOpt(request.getResourceName(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE, OptConstants.OPT_TYPE.NEW);
}
@ -383,7 +387,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
request.setCanvasStyleData(templateStyle);
//Store static resource into the server
staticResourceServer.saveFilesToServe(staticResource);
return new DataVisualizationVO(newDvId, name, dvType, version, templateStyle, templateData, canvasViewInfo, null);
return new DataVisualizationVO(newDvId, name, dvType, version, templateStyle, templateData,appData, canvasViewInfo, null);
}
@Override
@ -415,10 +419,10 @@ public class DataVisualizationServer implements DataVisualizationApi {
List<AppCoreDatasourceVO> datasourceVOInfo = null;
List<AppCoreDatasourceTaskVO> datasourceTaskVOInfo = null;
//TODO 获取所有视图信息
if (CollectionUtils.isEmpty(viewIds)) {
if (!CollectionUtils.isEmpty(viewIds)) {
chartViewVOInfo = appTemplateMapper.findAppViewInfo(viewIds);
}
if (CollectionUtils.isEmpty(dsIds)) {
if (!CollectionUtils.isEmpty(dsIds)) {
datasetGroupVOInfo = appTemplateMapper.findAppDatasetGroupInfo(dsIds);
datasetTableVOInfo = appTemplateMapper.findAppDatasetTableInfo(dsIds);
datasetTableFieldVOInfo = appTemplateMapper.findAppDatasetTableFieldInfo(dsIds);
@ -430,7 +434,7 @@ public class DataVisualizationServer implements DataVisualizationApi {
List<VisualizationLinkageFieldVO> linkageFieldVOInfo = appTemplateMapper.findAppLinkageFieldInfo(dvId);
List<VisualizationLinkJumpVO> linkJumpVOInfo = appTemplateMapper.findAppLinkJumpInfo(dvId);
List<VisualizationLinkJumpInfoVO> linkJumpInfoVOInfo = appTemplateMapper.findAppLinkJumpInfoInfo(dvId);
List<VisualizationLinkJumpTargetViewInfoVO> listJumpTargetViewInfoVO = appTemplateMapper.findAppJumpTargetViewInfo(dvId);
List<VisualizationLinkJumpTargetViewInfoVO> listJumpTargetViewInfoVO = appTemplateMapper.findAppLinkJumpTargetViewInfoInfo(dvId);
return new VisualizationExport2AppVO(chartViewVOInfo, datasetGroupVOInfo, datasetTableVOInfo,
datasetTableFieldVOInfo, datasourceVOInfo, datasourceTaskVOInfo,

View File

@ -48,3 +48,7 @@ INSERT INTO `core_copilot_config` VALUES (1, 'https://copilot-demo.test.fit2clou
UPDATE `core_sys_setting` SET `pkey` = 'ai.baseUrl', `pval` = 'https://maxkb.fit2cloud.com/ui/chat/2ddd8b594ce09dbb?mode=embed', `type` = 'text', `sort` = 0 WHERE `id` = 3;
ALTER TABLE `visualization_template`
MODIFY COLUMN `node_type` varchar(255) NULL DEFAULT NULL COMMENT '节点类型 app or template 应用 或者 模板' AFTER `dv_type`,
ADD COLUMN `app_data` longtext NULL COMMENT 'app数据' AFTER `dynamic_data`;

View File

@ -69,3 +69,7 @@ CREATE TABLE `core_api_traffic`
PRIMARY KEY (`id`)
);
ALTER TABLE `visualization_template`
MODIFY COLUMN `node_type` varchar(255) NULL DEFAULT NULL COMMENT '节点类型 app or template 应用 或者 模板' AFTER `dv_type`,
ADD COLUMN `app_data` longtext NULL COMMENT 'app数据' AFTER `dynamic_data`;

View File

@ -95,10 +95,10 @@ export const getComponentInfo = dvId => {
})
}
export const export2AppCheck = dvId => {
return request.get({
url: '/dataVisualization/export2AppCheck/' + dvId,
method: 'get',
export const export2AppCheck = params => {
return request.post({
url: '/dataVisualization/export2AppCheck',
data: params,
loading: true
})
}

View File

@ -24,6 +24,7 @@ import OuterParamsSet from '@/components/visualization/OuterParamsSet.vue'
import MultiplexingCanvas from '@/views/common/MultiplexingCanvas.vue'
import ComponentButtonLabel from '@/components/visualization/ComponentButtonLabel.vue'
import DeFullscreen from '@/components/visualization/common/DeFullscreen.vue'
import DeAppApply from '@/views/common/DeAppApply.vue'
let nameEdit = ref(false)
let inputName = ref('')
let nameInput = ref(null)
@ -32,7 +33,8 @@ const snapshotStore = snapshotStoreWithOut()
const { styleChangeTimes, snapshotIndex } = storeToRefs(snapshotStore)
const resourceGroupOpt = ref(null)
const dvToolbarMain = ref(null)
const { componentData, canvasStyleData, dvInfo, editMode } = storeToRefs(dvMainStore)
const { componentData, canvasStyleData, canvasViewInfo, dvInfo, editMode } =
storeToRefs(dvMainStore)
let scaleEdit = 100
const { wsCache } = useCache('localStorage')
const dvModel = 'dataV'
@ -342,6 +344,12 @@ const fullScreenPreview = () => {
cur-canvas-type="dataV"
ref="resourceGroupOpt"
/>
<de-app-apply
ref="resourceGroupOpt"
:component-data="componentData"
:dv-info="dvInfo"
:canvas-view-info="canvasViewInfo"
></de-app-apply>
</div>
<de-fullscreen ref="fullScreeRef" show-position="dvEdit"></de-fullscreen>
<multiplexing-canvas ref="multiplexingRef"></multiplexing-canvas>

View File

@ -1,7 +1,7 @@
<template>
<el-drawer
:title="'应用导出'"
v-model:visible="state.applyDownloadDrawer"
v-model="state.applyDownloadDrawer"
custom-class="de-user-drawer"
size="600px"
direction="rtl"
@ -11,13 +11,12 @@
ref="applyDownloadForm"
:model="state.form"
:rules="state.rule"
size="small"
class="de-form-item"
label-width="180px"
label-position="right"
label-position="top"
>
<el-form-item :label="'应用名称'" prop="appName">
<el-input v-model="form.appName" autocomplete="off" :placeholder="'请输入名称'" />
<el-input v-model="state.form.appName" autocomplete="off" :placeholder="'请输入名称'" />
</el-form-item>
<el-form-item :label="'应用版本号'" prop="version">
<el-input v-model="state.form.version" autocomplete="off" />
@ -38,22 +37,43 @@
</el-form-item>
</el-form>
</div>
<div class="app-export-bottom">
<template #footer>
<div class="apply" style="width: 100%">
<el-button secondary @click="close">{{ $t('commons.cancel') }} </el-button>
<el-button type="primary" @click="downloadApp">{{ $t('app_template.export') }} </el-button>
<el-button type="primary" @click="downloadApp">导出</el-button>
</div>
</div>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import { ElButton, ElDrawer, ElForm, ElFormItem, ElInput } from 'element-plus-secondary'
import { reactive, ref } from 'vue'
import { reactive, ref, toRefs } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
import { export2AppCheck } from '@/api/visualization/dataVisualization'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
const { t } = useI18n()
const emits = defineEmits(['closeDraw', 'downLoadApp'])
const applyDownloadForm = ref(null)
const dvMainStore = dvMainStoreWithOut()
const props = defineProps({
componentData: {
type: Object,
required: true
},
canvasViewInfo: {
type: Object,
required: true
},
dvInfo: {
type: Object,
required: true
}
})
const { componentData, canvasViewInfo, dvInfo } = toRefs(props)
const state = reactive({
applyDownloadDrawer: false,
form: {
@ -61,7 +81,7 @@ const state = reactive({
icon: null,
version: null,
creator: null,
required: '1.16.0',
required: '2.8.0',
description: null
},
rule: {
@ -105,6 +125,7 @@ const state = reactive({
})
const init = params => {
console.log('init==')
state.applyDownloadDrawer = true
state.form = params
}
@ -114,11 +135,44 @@ const close = () => {
state.applyDownloadDrawer = false
}
const gatherAppInfo = (viewIds, dsIds) => {
componentData.value.forEach(item => {
if (item.component === 'UserView' && canvasViewInfo.value[item.id]) {
const viewDetails = canvasViewInfo.value[item.id]
const { id, tableId } = viewDetails
viewIds.push(id)
dsIds.push(tableId)
} else if (item.component === 'Group') {
item.propValue.forEach(groupItem => {
const viewDetails = canvasViewInfo.value[groupItem.id]
const { id, tableId } = viewDetails
viewIds.push(id)
dsIds.push(tableId)
})
} else if (item.component === 'DeTabs') {
item.propValue.forEach(tabItem => {
tabItem.componentData.forEach(tabComponent => {
const viewDetails = canvasViewInfo.value[tabComponent.id]
const { id, tableId } = viewDetails
viewIds.push(id)
dsIds.push(tableId)
})
})
}
})
}
const downloadApp = () => {
applyDownloadForm.value?.validate(valid => {
if (valid) {
emits('downLoadApp', state.form)
state.applyDownloadDrawer = false
const viewIds = []
const dsIds = []
gatherAppInfo(viewIds, dsIds)
export2AppCheck({ dvId: dvInfo.value.id, viewIds, dsIds }).then(rsp => {
const params = { ...rsp.data, ...state.form }
emits('downLoadApp', params)
state.applyDownloadDrawer = false
})
} else {
return false
}

View File

@ -537,7 +537,8 @@ export async function decompressionPre(params, callBack) {
deTemplateData = {
canvasStyleData: sourceCanvasStyle,
componentData: sourceComponentData,
canvasViewInfo: deTemplateDataTemp['canvasViewInfo']
canvasViewInfo: deTemplateDataTemp['canvasViewInfo'],
appData: deTemplateDataTemp['appData']
}
})
.catch(e => {

View File

@ -35,7 +35,7 @@ export function imgUrlTrans(url) {
}
}
export function download2AppTemplate(downloadType, canvasDom, name, callBack?) {
export function download2AppTemplate(downloadType, canvasDom, name, attachParams, callBack?) {
try {
findStaticSource(function (staticResource) {
html2canvas(canvasDom).then(canvas => {
@ -50,11 +50,13 @@ export function download2AppTemplate(downloadType, canvasDom, name, callBack?) {
templateType: 'self',
snapshot: snapshot,
dvType: dvInfo.value.type,
nodeType: downloadType,
version: 3,
canvasStyleData: JSON.stringify(canvasStyleData.value),
componentData: JSON.stringify(componentData.value),
dynamicData: JSON.stringify(canvasViewDataTemplate),
staticResource: JSON.stringify(staticResource || {})
staticResource: JSON.stringify(staticResource || {}),
appData: JSON.stringify(attachParams || {})
}
const blob = new Blob([JSON.stringify(templateInfo)], { type: '' })
if (downloadType === 'template') {

View File

@ -0,0 +1,256 @@
<template>
<el-drawer
:title="'保存应用'"
v-model="state.appApplyDrawer"
custom-class="de-user-drawer"
size="600px"
direction="rtl"
>
<div class="app-export">
<el-form
ref="appSaveForm"
:model="state.form"
:rules="state.rule"
class="de-form-item"
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-input v-model="state.form.name" autocomplete="off" :placeholder="'请输入名称'" />
</el-form-item>
<el-form-item :label="dvPreName + '所在位置'" prop="version">
<el-tree-select
style="width: 100%"
@keydown.stop
@keyup.stop
v-model="state.form.pid"
:data="state.dvTree"
:props="state.propsTree"
@node-click="dvTreeSelect"
:filter-method="dvTreeFilterMethod"
:render-after-expand="false"
filterable
>
<template #default="{ data: { name } }">
<span class="custom-tree-node">
<el-icon>
<Icon name="dv-folder"></Icon>
</el-icon>
<span :title="name">{{ name }}</span>
</span>
</template>
</el-tree-select>
</el-form-item>
<el-form-item :label="'数据集分组名称'" prop="appName">
<el-input
v-model="state.form.datasetFolderName"
autocomplete="off"
:placeholder="'请输入名称'"
/>
</el-form-item>
<el-form-item label="数据集分组位置" prop="version">
<el-tree-select
style="width: 100%"
@keydown.stop
@keyup.stop
v-model="state.form.datasetFolderPid"
:data="state.dvTree"
:props="state.propsTree"
@node-click="dvTreeSelect"
:filter-method="dvTreeFilterMethod"
:render-after-expand="false"
filterable
>
<template #default="{ data: { name } }">
<span class="custom-tree-node">
<el-icon>
<Icon name="dv-folder"></Icon>
</el-icon>
<span :title="name">{{ name }}</span>
</span>
</template>
</el-tree-select>
</el-form-item>
<div class="de-row-rules" style="margin: 0 0 16px">
<span>数据源信息</span>
</div>
<div>数据源信息配置</div>
</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>
</div>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import {
ElButton,
ElDrawer,
ElForm,
ElFormItem,
ElInput,
ElTreeSelect
} from 'element-plus-secondary'
import { computed, reactive, ref, toRefs } from 'vue'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const emits = defineEmits(['closeDraw', 'downLoadApp'])
const appSaveForm = ref(null)
const props = defineProps({
componentData: {
type: Object,
required: true
},
canvasViewInfo: {
type: Object,
required: true
},
dvInfo: {
type: Object,
required: true
},
dvType: {
type: String,
default: 'dashboard'
}
})
const { componentData, canvasViewInfo, dvInfo, dvType } = toRefs(props)
const dvPreName = computed(() => (dvType.value === 'dashboard' ? '仪表板' : '数据大屏'))
const state = reactive({
appApplyDrawer: false,
dvTree: [],
propsTree: {
label: 'name',
children: 'children',
isLeaf: node => !node.children?.length
},
form: {
pid: '',
name: '新建',
datasetFolderPid: null,
datasetFolderName: null,
datasourceMap: {} // ID
},
rule: {
name: [
{
required: true,
min: 2,
max: 25,
message: t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
pid: [
{
required: true,
min: 2,
max: 25,
message: '请选择所属文件夹',
trigger: 'blur'
}
],
datasetFolderName: [
{
required: true,
min: 2,
max: 25,
message: t('datasource.input_limit_2_25', [2, 25]),
trigger: 'blur'
}
],
datasetFolderPid: [
{
required: true,
min: 2,
max: 25,
message: '请选择数据集分组所属文件夹',
trigger: 'blur'
}
]
}
})
const init = params => {
console.log('init==')
state.appApplyDrawer = true
state.form = params
}
const dvTreeFilterMethod = value => {
state.dvTree = [...state.dvTree].filter(item => item.name.includes(value))
}
const dvTreeSelect = element => {
state.form.pid = element.id
}
const close = () => {
emits('closeDraw')
state.appApplyDrawer = false
}
const saveApp = () => {
appSaveForm.value?.validate(valid => {
if (valid) {
const viewIds = []
const dsIds = []
} else {
return false
}
})
}
defineExpose({
init
})
</script>
<style lang="less" scoped>
.app-export {
width: 100%;
height: calc(100% - 56px);
}
.app-export-bottom {
width: 100%;
height: 56px;
text-align: right;
}
:deep(.ed-drawer__body) {
padding-bottom: 0 !important;
}
.de-row-rules {
display: flex;
align-items: center;
position: relative;
font-size: 14px;
font-weight: 500;
line-height: 22px;
padding-left: 10px;
margin: 24px 0 16px 0;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 14px;
width: 2px;
background: #3370ff;
}
}
</style>

View File

@ -172,6 +172,9 @@ const initOpenHandler = newWindow => {
<el-dropdown-item style="width: 118px" @click="downloadAsAppTemplate('template')"
>模板</el-dropdown-item
>
<el-dropdown-item style="width: 118px" @click="downloadAsAppTemplate('app')"
>应用</el-dropdown-item
>
<el-dropdown-item @click="download('img')">{{
t('chart.image')
}}</el-dropdown-item>

View File

@ -104,16 +104,25 @@ const download = type => {
}, 200)
}
const downloadAsAppTemplate = downloadType => {
const fileDownload = (downloadType, attachParams) => {
downloadStatus.value = true
nextTick(() => {
const vueDom = previewCanvasContainer.value.querySelector('.canvas-container')
download2AppTemplate(downloadType, vueDom, state.dvInfo.name, () => {
download2AppTemplate(downloadType, vueDom, state.dvInfo.name, attachParams, () => {
downloadStatus.value = false
})
})
}
const downloadAsAppTemplate = downloadType => {
console.log('===test===' + downloadType)
if (downloadType === 'template') {
fileDownload(downloadType, null)
} else if (downloadType === 'app') {
downLoadToAppPre()
}
}
const downLoadToAppPre = () => {
const result = checkTemplate()
if (result && result.length > 0) {
@ -123,7 +132,7 @@ const downLoadToAppPre = () => {
appName: dvInfo.value.name,
icon: null,
version: '2.0',
creator: state.userLoginInfo?.nickName,
creator: state.userLoginInfo?.name,
required: '2.9.0',
description: null
})
@ -139,9 +148,6 @@ const checkTemplate = () => {
})
return templateViewNames.slice(1)
}
const downLoadToApp = appAttachInfo => {
// do attach
}
const slideOpenChange = () => {
slideShow.value = !slideShow.value
@ -182,7 +188,7 @@ const getPreviewStateInfo = () => {
}
const downLoadApp = appAttachInfo => {
downLoadToApp(appAttachInfo)
fileDownload('app', appAttachInfo)
}
const findUserData = callback => {
@ -291,7 +297,13 @@ onBeforeMount(() => {
</template>
</el-container>
</div>
<app-export-form ref="appExportFormRef" @downLoadApp="downLoadApp"></app-export-form>
<app-export-form
ref="appExportFormRef"
:dv-info="state.dvInfo"
:component-data="state.canvasDataPreview"
:canvas-view-info="state.canvasViewInfoPreview"
@downLoadApp="downLoadApp"
></app-export-form>
</template>
<style lang="less">

View File

@ -88,6 +88,7 @@ const leftSidebarRef = ref(null)
const dvLayout = ref(null)
const canvasCenterRef = ref(null)
const mainHeight = ref(300)
let createType = null
const state = reactive({
datasetTree: [],
scaleHistory: null,
@ -295,7 +296,7 @@ onMounted(async () => {
const pid = embeddedStore.pid || router.currentRoute.value.query.pid
const templateParams =
embeddedStore.templateParams || router.currentRoute.value.query.templateParams
const createType = embeddedStore.createType || router.currentRoute.value.query.createType
createType = embeddedStore.createType || router.currentRoute.value.query.createType
const opt = embeddedStore.opt || router.currentRoute.value.query.opt
const checkResult = await checkPer(dvId)
if (!checkResult) {

View File

@ -17,7 +17,7 @@
id="input"
ref="filesRef"
type="file"
accept=".DET2"
accept=".DET2,.DET2APP"
hidden
@change="handleFileChange"
/>
@ -127,10 +127,12 @@ const state = reactive({
pid: props.pid,
categories: [],
dvType: 'dashboard',
nodeType: 'template',
name: '',
templateStyle: null,
templateData: null,
dynamicData: null,
appData: null,
staticResource: null,
snapshot: '',
version: null
@ -265,8 +267,9 @@ const handleFileChange = e => {
state.templateInfo.templateData = state.importTemplateInfo['componentData']
state.templateInfo.snapshot = state.importTemplateInfo.snapshot
state.templateInfo.dynamicData = state.importTemplateInfo['dynamicData']
state.templateInfo.appData = state.importTemplateInfo['appData']
state.templateInfo.staticResource = state.importTemplateInfo['staticResource']
state.templateInfo['nodeType'] = 'template'
state.templateInfo['nodeType'] = state.importTemplateInfo['nodeType'] || 'template'
state.templateInfo['version'] = state.importTemplateInfo['version']
}
reader.readAsText(file)

View File

@ -76,6 +76,11 @@ public class VisualizationTemplateVO {
*/
private String dynamicData;
/**
* app数据
*/
private String appData;
/**
* 使用次数
*/

View File

@ -113,7 +113,7 @@ public interface DataVisualizationApi {
@Operation(summary = "仪表板视图明细数据")
List<VisualizationViewTableDTO> detailList(@PathVariable("dvId") Long dvId);
@GetMapping("/export2AppCheck")
@PostMapping("/export2AppCheck")
@Operation(summary = "仪表板视图明细数据")
VisualizationExport2AppVO export2AppCheck(@RequestBody VisualizationAppExportRequest appExportRequest);
}

View File

@ -168,8 +168,13 @@ public class DataVisualizationVO implements Serializable {
*/
private Integer weight;
/**
* 应用信息
*/
private String appData;
public DataVisualizationVO(Long id, String name, String type, Integer version, String canvasStyleData, String componentData, Map<Long, ChartViewDTO> canvasViewInfo, Map<Long, VisualizationTemplateExtendDataDTO> extendDataInfo) {
public DataVisualizationVO(Long id, String name, String type, Integer version, String canvasStyleData, String componentData,String appData, Map<Long, ChartViewDTO> canvasViewInfo, Map<Long, VisualizationTemplateExtendDataDTO> extendDataInfo) {
this.id = id;
this.name = name;
this.type = type;
@ -177,6 +182,7 @@ public class DataVisualizationVO implements Serializable {
this.componentData = componentData;
this.canvasViewInfo = canvasViewInfo;
this.extendDataInfo = extendDataInfo;
this.appData = appData;
this.version = version;
}
}