Merge pull request #9582 from dataease/dev-v2

merge v2.6.1
This commit is contained in:
fit2cloudrd 2024-05-10 11:38:48 +08:00 committed by GitHub
commit 8fb2ea224e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 205 additions and 70 deletions

View File

@ -673,7 +673,7 @@ public class ChartDataManage {
item[dataIndex] = null;
} else {
item[dataIndex] = new BigDecimal(cValue)
.divide(new BigDecimal(lastValue), 8, RoundingMode.HALF_UP)
.divide(new BigDecimal(lastValue).abs(), 8, RoundingMode.HALF_UP)
.subtract(new BigDecimal(1))
.setScale(8, RoundingMode.HALF_UP)
.toString();

View File

@ -3,6 +3,7 @@ package io.dataease.datasource.manage;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.dataease.datasource.dao.auto.entity.CoreDatasource;
import io.dataease.datasource.dao.auto.entity.CoreDeEngine;
import io.dataease.datasource.dao.auto.mapper.CoreDatasourceMapper;
import io.dataease.datasource.dao.auto.mapper.CoreDeEngineMapper;
import io.dataease.datasource.provider.EngineProvider;
import io.dataease.datasource.provider.ProviderUtil;
@ -21,7 +22,9 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -33,6 +36,9 @@ public class EngineManage {
@Resource
private CoreDeEngineMapper deEngineMapper;
@Resource
private CoreDatasourceMapper datasourceMapper;
public CoreDeEngine info() throws DEException {
List<CoreDeEngine> deEngines = deEngineMapper.selectList(null);
@ -89,6 +95,7 @@ public class EngineManage {
}
public void initSimpleEngine() throws Exception {
initLocalDataSource();
QueryWrapper<CoreDeEngine> queryWrapper = new QueryWrapper<>();
if (ModelUtils.isDesktop()) {
queryWrapper.eq("type", engineType.h2.name());
@ -147,4 +154,40 @@ public class EngineManage {
return alias;
}
}
public void initLocalDataSource(){
QueryWrapper<CoreDatasource> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id",985188400292302848L);
queryWrapper.ne("create_time",1715053684176L);
if(!datasourceMapper.exists(queryWrapper) && !ModelUtils.isDesktop()){
Pattern WITH_SQL_FRAGMENT = Pattern.compile("jdbc:mysql://(.*):(\\d+)/(.*)\\?(.*)");
Matcher matcher = WITH_SQL_FRAGMENT.matcher(env.getProperty("spring.datasource.url"));
if (!matcher.find()) {
return;
}
Map configuration = new HashMap<>();
configuration.put("dataBase",matcher.group(3));
configuration.put("username",env.getProperty("spring.datasource.username"));
configuration.put("password",env.getProperty("spring.datasource.password"));
configuration.put("host",matcher.group(1));
configuration.put("port",Integer.valueOf(matcher.group(2)));
configuration.put("extraParams","");
CoreDatasource initDatasource = new CoreDatasource();
initDatasource.setId(985188400292302848L);
initDatasource.setName("Demo");
initDatasource.setType("mysql");
initDatasource.setPid(0L);
initDatasource.setConfiguration(JsonUtil.toJSONString(configuration).toString());
initDatasource.setCreateTime(System.currentTimeMillis());
initDatasource.setUpdateTime(System.currentTimeMillis());
initDatasource.setCreateBy("1");
initDatasource.setUpdateBy(1L);
initDatasource.setStatus("success");
initDatasource.setTaskStatus("WaitingForExecution");
datasourceMapper.deleteById(985188400292302848L);
datasourceMapper.insert(initDatasource);
}
}
}

View File

@ -404,6 +404,9 @@ public class CalciteProvider {
" database = '%s' \n" +
" AND table = '%s' ", configuration.getDataBase(), datasourceRequest.getTable());
break;
case impala:
sql = String.format("DESCRIBE `%s`", datasourceRequest.getTable());
break;
default:
break;
}

View File

@ -13,18 +13,20 @@ import io.dataease.utils.IDUtils;
import io.dataease.utils.SystemSettingUtils;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
@Component
public class SysParameterManage {
@Value("${dataease.show-demo-tips:false}")
private boolean showDemoTips;
private static final String mapKey = "map.key";
@Resource
@ -93,7 +95,13 @@ public class SysParameterManage {
@XpackInteract(value = "perSetting", replace = true)
public List<Object> getUiList() {
return null;
Map<String, Object> loginTipsItem = new HashMap<>();
loginTipsItem.put("pkey", "showDemoTips");
loginTipsItem.put("pval", showDemoTips);
loginTipsItem.put("sort", 1);
List<Object> result = new ArrayList<>();
result.add(loginTipsItem);
return result;
}

View File

@ -29,7 +29,6 @@ set
where a.id = b.id and a.type = 'table-pivot';
INSERT INTO `core_datasource` (`id`, `name`, `description`, `type`, `pid`, `edit_type`, `configuration`, `create_time`, `update_time`, `update_by`, `create_by`, `status`, `qrtz_instance`, `task_status`) VALUES (985188400292302848, 'Demo', '', 'mysql', 0, NULL, '{\"dataBase\":\"dataease\",\"extraParams\":\"\",\"username\":\"root\",\"password\":\"Password123@mysql\",\"host\":\"mysql-de\",\"authMethod\":\"\",\"port\":3306,\"initialPoolSize\":5,\"minPoolSize\":5,\"maxPoolSize\":5,\"queryTimeout\":30}', 1715053684176, 1715100309074, 1, '1', 'Success', NULL, 'WaitingForExecution');
INSERT INTO `core_dataset_table` (`id`, `name`, `table_name`, `datasource_id`, `dataset_group_id`, `type`, `info`, `sql_variable_details`) VALUES (7193457660727922688, NULL, 'demo_tea_material', 985188400292302848, 985189703189925888, 'db', '{\"table\":\"demo_tea_material\",\"sql\":\"\"}', NULL);
INSERT INTO `core_dataset_table` (`id`, `name`, `table_name`, `datasource_id`, `dataset_group_id`, `type`, `info`, `sql_variable_details`) VALUES (7193537020143079424, NULL, 'demo_tea_order', 985188400292302848, 985189053949415424, 'db', '{\"table\":\"demo_tea_order\",\"sql\":\"\"}', NULL);

View File

@ -54,7 +54,9 @@ watch(
</el-icon>
<div class="filter-texts-container" ref="container">
<p v-for="(ele, index) in filterTexts" :key="ele" class="text">
{{ ele }}
<el-tooltip effect="dark" :content="ele" placement="top-start">
{{ ele }}
</el-tooltip>
<el-icon @click="clearFilter(index)">
<Icon name="icon_close_outlined"></Icon>
</el-icon>

View File

@ -852,11 +852,16 @@ defineExpose({
}
.head-filter {
flex: 1;
text-align: right;
display: flex;
align-items: center;
justify-content: end;
margin-right: 16px;
font-weight: 400;
font-size: 12px;
color: #646a73;
.ed-switch {
margin-left: 8px;
}
}
}

View File

@ -534,11 +534,16 @@ defineExpose({
}
.head-filter {
flex: 1;
text-align: right;
display: flex;
align-items: center;
justify-content: end;
margin-right: 16px;
font-weight: 400;
font-size: 12px;
color: #646a73;
.ed-switch {
margin-left: 8px;
}
}
}

View File

@ -70,7 +70,7 @@ const releaseSelect = inject('release-unmount-select', Function, true)
const queryDataForId = inject('query-data-for-id', Function, true)
const setDefaultMapValue = arr => {
const { displayId, field } = config.value
if (!displayId || displayId === field?.id) {
if (!displayId) {
return []
}
let defaultMapValue = {}

View File

@ -51,6 +51,7 @@ onMounted(() => {
.ai-main {
position: fixed;
border-radius: 5px;
border-top-right-radius: 0;
overflow: hidden;
height: 0;
bottom: 48px;

View File

@ -10,7 +10,7 @@ const setCollapse = () => {
<template>
<div class="de-collapse-bar" @click="setCollapse">
<el-icon>
<el-icon style="color: #646a73">
<Icon :name="!isCollapse ? 'icon_side-fold_outlined' : 'icon_side-expand_outlined'"></Icon>
</el-icon>
{{ !isCollapse ? '收起导航' : '' }}
@ -29,7 +29,6 @@ const setCollapse = () => {
font-size: 14px;
font-weight: 400;
line-height: 22px;
color: #646a73;
display: flex;
align-items: center;

View File

@ -17,7 +17,7 @@ const { start, done } = useNProgress()
const interactiveStore = interactiveStoreWithOut()
const { loadStart, loadDone } = usePageLoading()
const whiteList = ['/login'] // 不重定向白名单
const whiteList = ['/login', '/panel'] // 不重定向白名单
router.beforeEach(async (to, _, next) => {
start()

View File

@ -20,6 +20,7 @@ interface AppearanceState {
foot?: string
footContent?: string
loaded: boolean
showDemoTips?: boolean
}
const { wsCache } = useCache()
export const useAppearanceStore = defineStore('appearanceStore', {
@ -37,7 +38,8 @@ export const useAppearanceStore = defineStore('appearanceStore', {
name: '',
foot: 'false',
footContent: '',
loaded: false
loaded: false,
showDemoTips: false
}
},
getters: {
@ -91,6 +93,9 @@ export const useAppearanceStore = defineStore('appearanceStore', {
},
getFootContent(): string {
return this.footContent
},
getShowDemoTips(): boolean {
return this.showDemoTips
}
},
actions: {
@ -126,6 +131,10 @@ export const useAppearanceStore = defineStore('appearanceStore', {
if (!resData?.length) {
return
}
if (resData.length === 1 && resData[0]?.pkey === 'showDemoTips') {
this.showDemoTips = resData[0].pval
return
}
const data: AppearanceState = { loaded: false }
resData.forEach(item => {
data[item.pkey] = item.pval

View File

@ -402,3 +402,10 @@ strong {
.ed-picker__popper {
--ed-datepicker-border-color: #DEE0E3 !important;
}
.ed-dialog__headerbtn {
top: 21px !important;
display: flex;
align-items: center;
justify-content: center
}

View File

@ -226,6 +226,7 @@ onMounted(() => {
<el-dropdown-item @click.prevent>
<el-dropdown
:effect="themes"
popper-class="data-dropdown_popper_mr9"
placement="right-start"
style="width: 100%; height: 100%"
@command="sort"
@ -305,6 +306,7 @@ onMounted(() => {
<el-dropdown
:effect="themes"
placement="right-start"
popper-class="data-dropdown_popper_mr9"
style="width: 100%; height: 100%"
@command="dateStyle"
>
@ -438,6 +440,7 @@ onMounted(() => {
<el-dropdown
:effect="themes"
placement="right-start"
popper-class="data-dropdown_popper_mr9"
style="width: 100%; height: 100%"
@command="datePattern"
>
@ -695,6 +698,9 @@ span {
}
</style>
<style lang="less">
.data-dropdown_popper_mr9 {
margin-left: -9px !important;
}
.menu-item-padding {
span {
font-size: 14px;

View File

@ -349,6 +349,7 @@ onMounted(() => {
<el-dropdown
:effect="themes"
placement="right-start"
popper-class="data-dropdown_popper_mr9"
style="width: 100%"
@command="switchChartType"
>
@ -403,6 +404,7 @@ onMounted(() => {
<el-dropdown
:effect="themes"
placement="right-start"
popper-class="data-dropdown_popper_mr9"
style="width: 100%; height: 100%"
@command="summary"
>
@ -583,6 +585,7 @@ onMounted(() => {
<el-dropdown
placement="right-start"
:effect="themes"
popper-class="data-dropdown_popper_mr9"
style="width: 100%; height: 100%"
@command="quickCalc"
>
@ -670,6 +673,7 @@ onMounted(() => {
<el-dropdown
:effect="themes"
placement="right-start"
popper-class="data-dropdown_popper_mr9"
style="width: 100%; height: 100%"
@command="sort"
>
@ -958,6 +962,9 @@ span {
}
</style>
<style lang="less">
.data-dropdown_popper_mr9 {
margin-left: -9px !important;
}
.menu-item-padding {
span {
font-size: 14px;

View File

@ -145,7 +145,7 @@ initCompareType()
>本期数据 - 上期数据</span
>
<span v-else-if="compareItem.compareCalc.resultData === 'percent'" class="exp-style"
>(本期数据 / 上期数据 - 1) * 100%</span
>(本期数据 / |上期数据| - 1) * 100%</span
>
</el-form-item>
</el-form>

View File

@ -15,7 +15,8 @@ import {
import {
AntVAbstractChartView,
AntVDrawOptions,
ChartLibraryType
ChartLibraryType,
ChartWrapper
} from '@/views/chart/components/js/panel/types'
import { getEngine } from '@antv/g2/esm/core'
import { handleEmptyDataStrategy } from '../../../util'
@ -32,6 +33,38 @@ export interface G2PlotDrawOptions<O> extends AntVDrawOptions<O> {
quadrantDefaultBaseline?: (...args: any) => void
}
/**
* 图表对象包装类一个图表里面可能有多个对象实例
*/
export class G2PlotWrapper<O extends PickOptions, P extends Plot<O>> extends ChartWrapper<
P | Array<P>
> {
constructor(chartInstance: P | Array<P>) {
super()
this.chartInstance = chartInstance
}
destroy = () => {
if (!this.chartInstance) {
return
}
if (Array.isArray(this.chartInstance)) {
this.chartInstance?.forEach(p => p.destroy())
} else {
this.chartInstance?.destroy()
}
}
render = () => {
if (!this.chartInstance) {
return
}
if (Array.isArray(this.chartInstance)) {
this.chartInstance?.forEach(p => p.render())
} else {
this.chartInstance?.render()
}
}
}
/**
* G2Plot 的图表抽象类
*/
@ -46,7 +79,7 @@ export abstract class G2PlotChartView<
* @param drawOptions 图表配置参数
* @return 生成的图表对象类型为 Plot 的子类
*/
public abstract drawChart(drawOptions: G2PlotDrawOptions<P>): P
public abstract drawChart(drawOptions: G2PlotDrawOptions<P>): G2PlotWrapper<O, P> | P
protected configTheme(chart: Chart, options: O): O {
const theme = getTheme(chart)

View File

@ -16,7 +16,11 @@ export enum ChartLibraryType {
RICH_TEXT = 'rich-text',
INDICATOR = 'indicator'
}
export abstract class ChartWrapper<O> {
chartInstance: O
abstract render: () => any
abstract destroy: () => any
}
export abstract class AbstractChartView {
render: ChartRenderType
library: ChartLibraryType

View File

@ -1,6 +1,5 @@
<script lang="ts" setup>
import { ref, onMounted, unref, onBeforeUnmount, computed } from 'vue'
import { XpackComponent } from '@/components/plugin'
import { ElMessage, ElMessageBox } from 'element-plus-secondary'
import MobileBackgroundSelector from './MobileBackgroundSelector.vue'
import ComponentWrapper from '@/components/data-visualization/canvas/ComponentWrapper.vue'
@ -47,18 +46,6 @@ const iframeSrc = computed(() => {
? `${embeddedStore.baseUrl}mobile.html#/panel`
: './mobile.html#/panel'
})
const openHandler = ref(null)
const initOpenHandler = newWindow => {
if (openHandler?.value && !!embeddedStore.baseUrl) {
const pm = {
methodName: 'initOpenHandler',
args: newWindow
}
openHandler.value.invokeMethod(pm)
}
}
const handleLoad = () => {
mobileStatusChange(
'panelInit',
@ -69,7 +56,8 @@ const handleLoad = () => {
),
canvasStyleData: JSON.parse(JSON.stringify(unref(canvasStyleData))),
canvasViewInfo: JSON.parse(JSON.stringify(unref(canvasViewInfo))),
dvInfo: JSON.parse(JSON.stringify(unref(dvInfo)))
dvInfo: JSON.parse(JSON.stringify(unref(dvInfo))),
isEmbedded: !!embeddedStore.baseUrl
})
)
)
@ -79,7 +67,19 @@ const componentDataNotInMobile = computed(() => {
return componentData.value.filter(ele => !ele.inMobile)
})
const newWindow = ref()
const hanedleMessage = event => {
if (event.data?.msgOrigin === 'de-fit2cloud' && !!embeddedStore.token) {
const params = {
embeddedToken: embeddedStore.token
}
params['de-embedded'] = true
const contentWindow = newWindow.value.contentWindow
console.log('call back from dataease!', contentWindow)
contentWindow.postMessage(params, '*')
return
}
if (event.data.type === 'panelInit') {
loadCanvasData()
}
@ -95,7 +95,7 @@ const hanedleMessage = event => {
})
}
if (event.data.type === 'mobileSaveFromMobile') {
if (['mobileSaveFromMobile', 'mobilePatchFromMobile'].includes(event.data.type)) {
componentData.value.forEach(ele => {
const com = event.data.value[ele.id]
if (!!com) {
@ -117,8 +117,14 @@ const hanedleMessage = event => {
}
}
})
}
if (event.data.type === 'mobileSaveFromMobile') {
saveCanvasWithCheckFromMobile()
}
if (event.data.type === 'mobilePatchFromMobile') {
emits('pcMode')
}
}
const saveCanvasWithCheckFromMobile = () => {
@ -146,7 +152,6 @@ const setMobileStyle = debounce(() => {
transformOrigin: '0 0'
}
}, 100)
const newWindow = ref()
onMounted(() => {
window.addEventListener('message', hanedleMessage)
window.addEventListener('resize', setMobileStyle)
@ -158,9 +163,6 @@ onMounted(() => {
}
})
setMobileStyle()
setTimeout(() => {
initOpenHandler(newWindow.value)
}, 300)
})
onBeforeUnmount(() => {
@ -179,7 +181,7 @@ const changeTimes = ref(0)
const activeCollapse = ref('com')
const handleBack = () => {
if (!changeTimes.value) {
emits('pcMode')
mobileStatusChange('mobilePatch', undefined)
return
}
ElMessageBox.confirm('当前的更改尚未保存,确定退出吗?', {
@ -188,7 +190,9 @@ const handleBack = () => {
autofocus: false,
showClose: false
}).then(() => {
emits('pcMode')
setTimeout(() => {
mobileStatusChange('mobilePatch', undefined)
}, 100)
})
}
@ -274,7 +278,6 @@ const save = () => {
</div>
</div>
</div>
<XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" />
</template>
<style lang="less" scoped>

View File

@ -154,7 +154,7 @@ onMounted(async () => {
}
let deTemplateData
if (createType === 'template') {
const templateParamsApply = JSON.parse(Base64.decode(templateParams + ''))
const templateParamsApply = JSON.parse(decodeURIComponent(Base64.decode(templateParams + '')))
await decompressionPre(templateParamsApply, result => {
deTemplateData = result
})

View File

@ -261,7 +261,7 @@ onMounted(async () => {
}
let deTemplateData
if (createType === 'template') {
const templateParamsApply = JSON.parse(Base64.decode(templateParams + ''))
const templateParamsApply = JSON.parse(decodeURIComponent(Base64.decode(templateParams + '')))
await decompressionPre(templateParamsApply, result => {
deTemplateData = result
})

View File

@ -35,12 +35,13 @@ const slogan = ref(null)
const footContent = ref(null)
const loginErrorMsg = ref('')
const xpackLoginHandler = ref()
const showDempTips = ref(false)
const demoTips = '账号admin 密码DataEase@123456 每晚 00:00 重置数据'
const state = reactive({
loginForm: {
username: '',
password: ''
},
uiInfo: {},
footContent: ''
})
const checkUsername = value => {
@ -163,6 +164,7 @@ const showLoginErrorMsg = () => {
}
const loadArrearance = () => {
showDempTips.value = appearanceStore.getShowDemoTips
if (appearanceStore.getBg) {
loginImageUrl.value = appearanceStore.getBg
}
@ -307,15 +309,8 @@ onMounted(() => {
>
{{ t('login.btn') }}
</el-button>
<div
v-if="
state.uiInfo &&
state.uiInfo['ui.demo.tips'] &&
state.uiInfo['ui.demo.tips'].paramValue
"
class="demo-tips"
>
{{ state.uiInfo['ui.demo.tips'].paramValue }}
<div v-if="showDempTips" class="demo-tips">
<span>{{ demoTips }}</span>
</div>
</div>
</div>
@ -426,12 +421,13 @@ onMounted(() => {
}
.demo-tips {
margin-top: 20px;
position: absolute;
font-size: 18px;
color: #f56c6c;
letter-spacing: 0;
line-height: 18px;
text-align: center;
top: 120px;
@media only screen and (max-width: 1280px) {
margin-top: 20px;
}
@ -465,6 +461,7 @@ onMounted(() => {
}
.login-btn {
position: relative;
margin-bottom: 120px;
.submit {
width: 100%;

View File

@ -1,9 +1,9 @@
<script lang="ts" setup>
import { onBeforeMount, ref, onBeforeUnmount } from 'vue'
import { useEmitt } from '@/hooks/web/useEmitt'
import { XpackComponent } from '@/components/plugin'
import eventBus from '@/utils/eventBus'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { XpackComponent } from '@/components/plugin'
import DePreviewMobile from './MobileInPc.vue'
const panelInit = ref(false)
const dvMainStore = dvMainStoreWithOut()
@ -19,7 +19,7 @@ const checkItemPosition = component => {
const hanedleMessage = event => {
if (event.data.type === 'panelInit') {
const { componentData, canvasStyleData, dvInfo, canvasViewInfo } = event.data.value
const { componentData, canvasStyleData, dvInfo, canvasViewInfo, isEmbedded } = event.data.value
componentData.forEach(ele => {
const { mx, my, mSizeX, mSizeY } = ele
ele.x = mx
@ -47,6 +47,7 @@ const hanedleMessage = event => {
dvMainStore.updateCurDvInfo(dvInfo)
dvMainStore.setCanvasViewInfo(canvasViewInfo)
eventBus.emit('doCanvasInit-canvas-main')
if (isEmbedded) return
panelInit.value = true
}
@ -61,10 +62,10 @@ const hanedleMessage = event => {
dvMainStore.setCanvasStyle(event.data.value)
}
if (event.data.type === 'mobileSave') {
window.top.postMessage(
if (['mobileSave', 'mobilePatch'].includes(event.data.type)) {
window.parent.postMessage(
{
type: 'mobileSaveFromMobile',
type: `${event.data.type}FromMobile`,
value: dvMainStore.componentData.reduce((pre, next) => {
const { x, y, sizeX, sizeY, id, component } = next
pre[id] = { x, y, sizeX, sizeY, component }
@ -90,11 +91,15 @@ const hanedleMessage = event => {
}
}
let p = null
const XpackLoaded = () => p(true)
onBeforeMount(async () => {
await new Promise(r => (p = r))
window.top.postMessage({ type: 'panelInit', value: true }, '*')
const initIframe = () => {
panelInit.value = false
setTimeout(() => {
panelInit.value = true
})
}
onBeforeMount(() => {
window.parent.postMessage({ type: 'panelInit', value: true }, '*')
window.addEventListener('message', hanedleMessage)
useEmitt({
name: 'onMobileStatusChange',
@ -105,7 +110,7 @@ onBeforeMount(async () => {
})
const mobileStatusChange = (type, value) => {
window.top.postMessage({ type, value }, '*')
window.parent.postMessage({ type, value }, '*')
if (type === 'delFromMobile') {
eventBus.emit('removeMatrixItemById-canvas-main', value)
}
@ -121,9 +126,8 @@ onBeforeUnmount(() => {
<de-preview-mobile v-if="panelInit"></de-preview-mobile>
</div>
<XpackComponent
jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvTmV3V2luZG93SGFuZGxlcg=="
@loaded="XpackLoaded"
@load-fail="XpackLoaded"
@initIframe="initIframe"
jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvRW50cmFuY2Vz"
/>
</template>

View File

@ -432,7 +432,7 @@ const apply = template => {
? '#/dvCanvas?opt=create&createType=template'
: '#/dashboard?opt=create&createType=template') +
'&templateParams=' +
Base64.encode(JSON.stringify(templateTemplate))
encodeURIComponent(Base64.encode(JSON.stringify(templateTemplate)))
let newWindow = null
let embeddedBaseUrl = ''
if (isDataEaseBi.value) {

View File

@ -235,7 +235,7 @@ const apply = () => {
? '#/dvCanvas?opt=create&createType=template'
: '#/dashboard?opt=create&createType=template') +
'&templateParams=' +
Base64.encode(JSON.stringify(templateTemplate))
encodeURIComponent(Base64.encode(JSON.stringify(templateTemplate)))
let newWindow = null
let embeddedBaseUrl = ''
if (isDataEaseBi.value) {

View File

@ -25,7 +25,7 @@
<mybatis-plus.version>3.5.6</mybatis-plus.version>
<h2.version>2.2.220</h2.version>
<knife4j.version>4.4.0</knife4j.version>
<calcite-core.version>1.35.7</calcite-core.version>
<calcite-core.version>1.35.8</calcite-core.version>
<commons-dbcp2.version>2.6.0</commons-dbcp2.version>
<antlr.version>3.5.2</antlr.version>
<java-jwt.version>3.12.1</java-jwt.version>