forked from github/dataease
Merge branch 'dev-v2' into pr@dev@refactor_tree-sort
This commit is contained in:
commit
9c21ae0d3b
@ -26,6 +26,6 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
sourcemap: true
|
||||
sourcemap: false
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,10 @@ const getPrefix = (): string => {
|
||||
url = ele.src
|
||||
}
|
||||
if (url.includes(suffix)) {
|
||||
prefix = new URL(url).origin
|
||||
const { origin, pathname } = new URL(url)
|
||||
const splitArr = pathname.split('/')
|
||||
splitArr.pop()
|
||||
prefix = `${origin}${splitArr.join('/')}`
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -23,15 +23,18 @@ const { start, done } = useNProgress()
|
||||
const { loadStart, loadDone } = usePageLoading()
|
||||
|
||||
const whiteList = ['/login', '/de-link', '/chart-view'] // 不重定向白名单
|
||||
|
||||
const embeddedWhiteList = ['/dvCanvas', '/dashboard']
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
start()
|
||||
loadStart()
|
||||
|
||||
if (isMobile() && to.name !== 'link') {
|
||||
if (isMobile()) {
|
||||
done()
|
||||
loadDone()
|
||||
window.location.href = window.origin + '/mobile.html#/index'
|
||||
if (to.name === 'link') {
|
||||
window.location.href = window.origin + '/mobile.html#' + to.path
|
||||
} else {
|
||||
window.location.href = window.origin + '/mobile.html#/index'
|
||||
}
|
||||
}
|
||||
let isDesktop = wsCache.get('app.desktop')
|
||||
if (isDesktop === null) {
|
||||
@ -96,7 +99,11 @@ router.beforeEach(async (to, from, next) => {
|
||||
next(nextData)
|
||||
}
|
||||
} else {
|
||||
if (whiteList.indexOf(to.path) !== -1 || to.path.startsWith('/de-link/')) {
|
||||
if (
|
||||
embeddedWhiteList.includes(to.path) ||
|
||||
whiteList.indexOf(to.path) !== -1 ||
|
||||
to.path.startsWith('/de-link/')
|
||||
) {
|
||||
permissionStore.setCurrentPath(to.path)
|
||||
next()
|
||||
} else {
|
||||
|
@ -39,7 +39,7 @@ router.beforeEach(async (to, _, next) => {
|
||||
next()
|
||||
}
|
||||
} else {
|
||||
if (whiteList.includes(to.path)) {
|
||||
if (whiteList.includes(to.path) || to.path.includes('/de-link')) {
|
||||
next()
|
||||
} else {
|
||||
next('/login') // 否则全部重定向到登录页
|
||||
|
@ -31,6 +31,13 @@ export const routes: AppRouteRecordRaw[] = [
|
||||
meta: {},
|
||||
component: () => import('@/views/mobile/panel/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/de-link/:uuid',
|
||||
name: 'link',
|
||||
hidden: true,
|
||||
meta: {},
|
||||
component: () => import('@/views/share/link/mobile.vue')
|
||||
},
|
||||
{
|
||||
path: '/panel/mobile',
|
||||
name: 'mobile',
|
||||
|
@ -48,6 +48,16 @@ export const userStore = defineStore('embedded', {
|
||||
},
|
||||
getResourceId(): string {
|
||||
return this.resourceId
|
||||
},
|
||||
getIframeData(): any {
|
||||
return {
|
||||
embeddedToken: this.token,
|
||||
busiFlag: this.busiFlag,
|
||||
type: this.type,
|
||||
dvId: this.dvId,
|
||||
chartId: this.chartId,
|
||||
pid: this.pid
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@ -74,6 +84,14 @@ export const userStore = defineStore('embedded', {
|
||||
},
|
||||
setResourceId(resourceId: string) {
|
||||
this.resourceId = resourceId
|
||||
},
|
||||
setIframeData(data: any) {
|
||||
this.type = data['type']
|
||||
this.token = data['embeddedToken']
|
||||
this.busiFlag = data['busiFlag']
|
||||
this.dvId = data['dvId']
|
||||
this.chartId = data['chartId']
|
||||
this.pid = data['pid']
|
||||
}
|
||||
}
|
||||
})
|
||||
|
77
core/core-frontend/src/utils/communication.ts
Normal file
77
core/core-frontend/src/utils/communication.ts
Normal file
@ -0,0 +1,77 @@
|
||||
export interface EmbeddedData {
|
||||
'de-embedded': boolean
|
||||
embeddedToken?: string
|
||||
busiFlag?: string
|
||||
type?: string
|
||||
dvId?: string
|
||||
chartId?: string
|
||||
pid: string
|
||||
}
|
||||
|
||||
export const communicationInit = cb => {
|
||||
window.addEventListener('message', event => {
|
||||
if (!event.data['de-embedded']) {
|
||||
return
|
||||
}
|
||||
const origin = event.origin
|
||||
console.log(origin)
|
||||
const embeddedData: EmbeddedData = event.data
|
||||
// validate origin
|
||||
if (cb) {
|
||||
cb(embeddedData)
|
||||
}
|
||||
})
|
||||
const readyData = {
|
||||
ready: true,
|
||||
msgOrigin: 'de-fit2cloud'
|
||||
}
|
||||
window.parent.postMessage(readyData, '*')
|
||||
}
|
||||
|
||||
export const initOpenHandler = (newWindow, data) => {
|
||||
if (!data.embeddedToken) {
|
||||
return
|
||||
}
|
||||
window['uuid'] = new Date().getTime()
|
||||
newWindow['uuid'] = window['uuid'] + 1
|
||||
newWindow['name'] = 'de-new-resource-window'
|
||||
window.addEventListener('message', event => {
|
||||
if (
|
||||
event.data?.msgOrigin !== 'de-inner-fit2cloud' ||
|
||||
event.origin !== window.origin ||
|
||||
event.source['uuid'] !== newWindow['uuid']
|
||||
) {
|
||||
return
|
||||
}
|
||||
data['de-inner-embedded'] = true
|
||||
if (event.data.ready) {
|
||||
newWindow.postMessage(data, '/')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const newWindowReady = async cb => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!window.opener || window['name'] !== 'de-new-resource-window') {
|
||||
return resolve(null)
|
||||
}
|
||||
window.addEventListener('message', event => {
|
||||
if (
|
||||
!event.data['de-inner-embedded'] ||
|
||||
event.origin !== window.origin ||
|
||||
window['uuid'] !== event.source['uuid'] - 1
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (cb) {
|
||||
cb(event.data)
|
||||
resolve(true)
|
||||
}
|
||||
})
|
||||
const readyData = {
|
||||
ready: true,
|
||||
msgOrigin: 'de-inner-fit2cloud'
|
||||
}
|
||||
window.opener.postMessage(readyData, '/')
|
||||
})
|
||||
}
|
@ -3,9 +3,8 @@ import { shallowRef, defineAsyncComponent, ref, onBeforeUnmount } from 'vue'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { useEmbedded } from '@/store/modules/embedded'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { onBeforeMount } from 'vue'
|
||||
const route = useRoute()
|
||||
import { communicationInit, EmbeddedData } from '@/utils/communication'
|
||||
const embeddedStore = useEmbedded()
|
||||
const appStore = useAppStoreWithOut()
|
||||
|
||||
@ -37,21 +36,6 @@ const componentMap = {
|
||||
ScreenPanel,
|
||||
DashboardPanel
|
||||
}
|
||||
const init = () => {
|
||||
appStore.setIsIframe(true)
|
||||
const busiFlag = route.query.busiFlag as string
|
||||
const dvId = route.query.dvId as string
|
||||
const chartId = route.query.chartId as string
|
||||
const type = route.query.type as string
|
||||
const embeddedToken = route.query.embeddedToken as string
|
||||
embeddedStore.setBusiFlag(busiFlag)
|
||||
embeddedStore.setToken(embeddedToken)
|
||||
embeddedStore.setChartId(chartId)
|
||||
embeddedStore.setDvId(dvId)
|
||||
embeddedStore.setType(type)
|
||||
currentComponent.value = componentMap[type || 'ViewWrapper']
|
||||
}
|
||||
|
||||
const iframeStyle = ref(null)
|
||||
const setStyle = debounce(() => {
|
||||
iframeStyle.value = {
|
||||
@ -60,9 +44,13 @@ const setStyle = debounce(() => {
|
||||
}
|
||||
}, 300)
|
||||
onBeforeMount(() => {
|
||||
communicationInit((data: EmbeddedData) => {
|
||||
embeddedStore.setIframeData(data)
|
||||
appStore.setIsIframe(true)
|
||||
currentComponent.value = componentMap[data.type || 'ViewWrapper']
|
||||
})
|
||||
window.addEventListener('resize', setStyle)
|
||||
setStyle()
|
||||
init()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
@ -20,6 +20,7 @@ import DeResourceCreateOptV2 from '@/views/common/DeResourceCreateOptV2.vue'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { findParentIdByChildIdRecursive } from '@/utils/canvasUtils'
|
||||
import treeSort from '@/utils/treeSortUtils'
|
||||
import { initOpenHandler } from '@/utils/communication'
|
||||
const { wsCache } = useCache()
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
@ -294,7 +295,8 @@ const operation = (cmd: string, data: BusiTreeNode, nodeType: string) => {
|
||||
curCanvasType.value === 'dataV'
|
||||
? `#/dvCanvas?opt=copy&pid=${params.pid}&dvId=${data.data}`
|
||||
: `#/dashboard?opt=copy&pid=${params.pid}&resourceId=${data.data}`
|
||||
window.open(baseUrl, '_blank')
|
||||
const newWindow = window.open(baseUrl, '_blank')
|
||||
initOpenHandler(newWindow, embeddedStore.getIframeData)
|
||||
})
|
||||
} else {
|
||||
resourceGroupOpt.value.optInit(nodeType, data, cmd, ['copy'].includes(cmd))
|
||||
@ -311,11 +313,13 @@ const addOperation = (
|
||||
if (cmd === 'newLeaf') {
|
||||
const baseUrl =
|
||||
curCanvasType.value === 'dataV' ? '#/dvCanvas?opt=create' : '#/dashboard?opt=create'
|
||||
let newWindow = null
|
||||
if (data?.id) {
|
||||
window.open(baseUrl + `&pid=${data.id}`, '_blank')
|
||||
newWindow = window.open(baseUrl + `&pid=${data.id}`, '_blank')
|
||||
} else {
|
||||
window.open(baseUrl, '_blank')
|
||||
newWindow = window.open(baseUrl, '_blank')
|
||||
}
|
||||
initOpenHandler(newWindow, embeddedStore.getIframeData)
|
||||
} else if (cmd === 'newFromTemplate') {
|
||||
// state.templateCreatePid = data?.id
|
||||
// // newFromTemplate
|
||||
@ -337,7 +341,8 @@ function createNewObject() {
|
||||
|
||||
const resourceEdit = resourceId => {
|
||||
const baseUrl = curCanvasType.value === 'dataV' ? '#/dvCanvas?dvId=' : '#/dashboard?resourceId='
|
||||
window.open(baseUrl + resourceId, '_blank')
|
||||
const newWindow = window.open(baseUrl + resourceId, '_blank')
|
||||
initOpenHandler(newWindow, embeddedStore.getIframeData)
|
||||
}
|
||||
|
||||
const resourceOptFinish = () => {
|
||||
@ -351,11 +356,13 @@ const resourceCreateFinish = templateData => {
|
||||
curCanvasType.value === 'dataV'
|
||||
? '#/dvCanvas?opt=create&createType=template'
|
||||
: '#/dashboard?opt=create&createType=template'
|
||||
let newWindow = null
|
||||
if (state.templateCreatePid) {
|
||||
window.open(baseUrl + `&pid=${state.templateCreatePid}`, '_blank')
|
||||
newWindow = window.open(baseUrl + `&pid=${state.templateCreatePid}`, '_blank')
|
||||
} else {
|
||||
window.open(baseUrl, '_blank')
|
||||
newWindow = window.open(baseUrl, '_blank')
|
||||
}
|
||||
initOpenHandler(newWindow, embeddedStore.getIframeData)
|
||||
}
|
||||
|
||||
const getParentKeys = (tree, targetKey, parentKeys = []) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import { computed, nextTick, onBeforeMount, onUnmounted, reactive, ref } from 'vue'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import findComponent from '../../utils/components'
|
||||
@ -22,6 +22,9 @@ import { useEmbedded } from '@/store/modules/embedded'
|
||||
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
||||
import { interactiveStoreWithOut } from '@/store/modules/interactive'
|
||||
import { watermarkFind } from '@/api/watermark'
|
||||
import { newWindowReady, EmbeddedData } from '@/utils/communication'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
const appStore = useAppStoreWithOut()
|
||||
const interactiveStore = interactiveStoreWithOut()
|
||||
const embeddedStore = useEmbedded()
|
||||
const { wsCache } = useCache()
|
||||
@ -93,8 +96,14 @@ const onMobileConfig = () => {
|
||||
mobileConfig.value = true
|
||||
})
|
||||
}
|
||||
const loadFinish = ref(false)
|
||||
// 全局监听按键事件
|
||||
onMounted(async () => {
|
||||
onBeforeMount(async () => {
|
||||
await newWindowReady((data: EmbeddedData) => {
|
||||
embeddedStore.setIframeData(data)
|
||||
appStore.setIsIframe(true)
|
||||
})
|
||||
loadFinish.value = true
|
||||
useEmitt({
|
||||
name: 'mobileConfig',
|
||||
callback: () => {
|
||||
@ -167,7 +176,7 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dv-common-layout dv-teleport-query" v-if="!mobileConfig">
|
||||
<div class="dv-common-layout dv-teleport-query" v-if="loadFinish && !mobileConfig">
|
||||
<DbToolbar />
|
||||
<el-container
|
||||
class="dv-layout-container"
|
||||
@ -233,7 +242,10 @@ onUnmounted(() => {
|
||||
</dv-sidebar>
|
||||
</el-container>
|
||||
</div>
|
||||
<MobileConfigPanel @pcMode="mobileConfig = false" v-else></MobileConfigPanel>
|
||||
<MobileConfigPanel
|
||||
@pcMode="mobileConfig = false"
|
||||
v-else-if="loadFinish && mobileConfig"
|
||||
></MobileConfigPanel>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
|
@ -28,6 +28,9 @@ import { useCache } from '@/hooks/web/useCache'
|
||||
import RealTimeListTree from '@/components/data-visualization/RealTimeListTree.vue'
|
||||
import { interactiveStoreWithOut } from '@/store/modules/interactive'
|
||||
import { watermarkFind } from '@/api/watermark'
|
||||
import { newWindowReady, EmbeddedData } from '@/utils/communication'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
const appStore = useAppStoreWithOut()
|
||||
const interactiveStore = interactiveStoreWithOut()
|
||||
const embeddedStore = useEmbedded()
|
||||
const { wsCache } = useCache()
|
||||
@ -198,6 +201,10 @@ const checkPer = async resourceId => {
|
||||
return check(wsCache.get('screen-weight'), resourceId, 4)
|
||||
}
|
||||
onMounted(async () => {
|
||||
await newWindowReady((data: EmbeddedData) => {
|
||||
embeddedStore.setIframeData(data)
|
||||
appStore.setIsIframe(true)
|
||||
})
|
||||
window.addEventListener('blur', releaseAttachKey)
|
||||
if (editMode.value === 'edit') {
|
||||
window.addEventListener('storage', eventCheck)
|
||||
|
92
core/core-frontend/src/views/share/link/mobile.vue
Normal file
92
core/core-frontend/src/views/share/link/mobile.vue
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<div class="mobile-link-container" v-loading="loading">
|
||||
<LinkError v-if="!loading && !linkExist" />
|
||||
<Exp v-else-if="!loading && linkExp" />
|
||||
<PwdTips v-else-if="!loading && !pwdValid" />
|
||||
<de-preview
|
||||
ref="dashboardPreview"
|
||||
v-if="state.canvasStylePreview && dataInitState"
|
||||
:component-data="state.canvasDataPreview"
|
||||
:canvas-style-data="state.canvasStylePreview"
|
||||
:canvas-view-info="state.canvasViewInfoPreview"
|
||||
:dv-info="state.dvInfo"
|
||||
:cur-gap="state.curPreviewGap"
|
||||
></de-preview>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, nextTick, ref, reactive } from 'vue'
|
||||
import { initCanvasDataMobile } from '@/utils/canvasUtils'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import DePreview from '@/components/data-visualization/canvas/DePreview.vue'
|
||||
import { ProxyInfo, shareProxy } from './ShareProxy'
|
||||
import Exp from './exp.vue'
|
||||
import LinkError from './error.vue'
|
||||
import PwdTips from './pwd.vue'
|
||||
const linkExist = ref(false)
|
||||
const loading = ref(true)
|
||||
const linkExp = ref(false)
|
||||
const pwdValid = ref(false)
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const state = reactive({
|
||||
canvasDataPreview: null,
|
||||
canvasStylePreview: null,
|
||||
canvasViewInfoPreview: null,
|
||||
dvInfo: {
|
||||
name: ''
|
||||
},
|
||||
curPreviewGap: 0
|
||||
})
|
||||
const dataInitState = ref(true)
|
||||
const dashboardPreview = ref(null)
|
||||
const loadCanvasData = (dvId, weight?) => {
|
||||
dataInitState.value = false
|
||||
initCanvasDataMobile(
|
||||
dvId,
|
||||
'dashboard',
|
||||
function ({
|
||||
canvasDataResult,
|
||||
canvasStyleResult,
|
||||
dvInfo,
|
||||
canvasViewInfoPreview,
|
||||
curPreviewGap
|
||||
}) {
|
||||
dvInfo['weight'] = weight
|
||||
state.canvasDataPreview = canvasDataResult
|
||||
state.canvasStylePreview = canvasStyleResult
|
||||
state.canvasViewInfoPreview = canvasViewInfoPreview
|
||||
state.dvInfo = dvInfo
|
||||
state.curPreviewGap = curPreviewGap
|
||||
dataInitState.value = true
|
||||
nextTick(() => {
|
||||
document.title = dvInfo.name
|
||||
dashboardPreview.value.restore()
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
onMounted(async () => {
|
||||
dvMainStore.setMobileInPc(true)
|
||||
const proxyInfo = (await shareProxy.loadProxy()) as ProxyInfo
|
||||
if (!proxyInfo?.resourceId) {
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
linkExist.value = true
|
||||
linkExp.value = !!proxyInfo.exp
|
||||
pwdValid.value = !!proxyInfo.pwdValid
|
||||
nextTick(() => {
|
||||
loadCanvasData(proxyInfo.resourceId, proxyInfo.type)
|
||||
dvMainStore.setPublicLinkStatus(true)
|
||||
loading.value = false
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.mobile-link-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user