feat: 嵌入式支持嵌入仪表板、数据大屏、数据源、数据集页面(带左侧的树形菜单)

This commit is contained in:
dataeaseShu 2024-01-08 16:32:23 +08:00
parent 125da76b11
commit 33a68c46f4
10 changed files with 225 additions and 97 deletions

View File

@ -1,6 +1,11 @@
<script setup lang="ts">
import { shallowRef, defineAsyncComponent } from 'vue'
import { shallowRef, defineAsyncComponent, onBeforeMount } from 'vue'
import { propTypes } from '@/utils/propTypes'
import { useAppStoreWithOut } from '@/store/modules/app'
const appStore = useAppStoreWithOut()
onBeforeMount(() => {
appStore.setIsDataEaseBi(true)
})
const VisualizationEditor = defineAsyncComponent(
() => import('@/views/data-visualization/index.vue')
)
@ -12,6 +17,10 @@ const Dataset = defineAsyncComponent(() => import('@/views/visualized/data/datas
const Datasource = defineAsyncComponent(
() => import('@/views/visualized/data/datasource/index.vue')
)
const ScreenPanel = defineAsyncComponent(() => import('@/views/data-visualization/PreviewShow.vue'))
const DashboardPanel = defineAsyncComponent(
() => import('@/views/dashboard/DashboardPreviewShow.vue')
)
const props = defineProps({
componentName: propTypes.string.def('DashboardEditor')
})
@ -23,7 +32,9 @@ const componentMap = {
ViewWrapper,
Dashboard,
Dataset,
Datasource
Datasource,
ScreenPanel,
DashboardPanel
}
currentComponent.value = componentMap[props.componentName]

View File

@ -89,7 +89,13 @@ const defaultOptions = {
class DataEaseBi {
baseUrl: string
token: string
type: 'DashboardEditor' | 'VisualizationEditor' | 'ViewWrapper' | 'Dashboard'
type:
| 'DashboardEditor'
| 'VisualizationEditor'
| 'ViewWrapper'
| 'Dashboard'
| 'ScreenPanel'
| 'DashboardPanel'
dvId: string
busiFlag: 'dashboard' | 'dataV'
resourceId: string

View File

@ -9,6 +9,7 @@ interface AppState {
title: string
dekey: string
desktop: boolean
isDataEaseBi: boolean
}
export const useAppStore = defineStore('app', {
@ -18,6 +19,7 @@ export const useAppStore = defineStore('app', {
pageLoading: false, // 路由跳转loading
title: 'DataEase',
dekey: 'DataEaseKey',
isDataEaseBi: false,
desktop: false
}
},
@ -31,7 +33,9 @@ export const useAppStore = defineStore('app', {
getTitle(): string {
return this.title
},
getIsDataEaseBi(): boolean {
return this.isDataEaseBi
},
getDekey(): string {
return this.dekey
},
@ -49,6 +53,9 @@ export const useAppStore = defineStore('app', {
setSize(size: boolean) {
this.size = size
},
setIsDataEaseBi(isDataEaseBi: boolean) {
this.isDataEaseBi = isDataEaseBi
},
setPageLoading(pageLoading: boolean) {
this.pageLoading = pageLoading
},

View File

@ -7,6 +7,7 @@ import { HandleMore } from '@/components/handle-more'
import DeResourceGroupOpt from '@/views/common/DeResourceGroupOpt.vue'
import { BusiTreeNode, BusiTreeRequest } from '@/models/tree/TreeNode'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { useAppStoreWithOut } from '@/store/modules/app'
import { storeToRefs } from 'pinia'
import DvHandleMore from '@/components/handle-more/src/DvHandleMore.vue'
import { interactiveStoreWithOut } from '@/store/modules/interactive'
@ -21,6 +22,7 @@ import { findParentIdByChildIdRecursive } from '@/utils/canvasUtils'
const { wsCache } = useCache()
const dvMainStore = dvMainStoreWithOut()
const appStore = useAppStoreWithOut()
const { dvInfo } = storeToRefs(dvMainStore)
const { t } = useI18n()
@ -53,34 +55,6 @@ const resourceCreateOpt = ref()
const returnMounted = ref(false)
const state = reactive({
resourceTree: [] as BusiTreeNode[],
menuList: [
{
label: '编辑',
command: 'edit',
svgName: 'dv-edit'
},
{
label: '复制',
command: 'copy',
svgName: 'dv-copy-dark'
},
{
label: '移动到',
command: 'move',
svgName: 'dv-move'
},
{
label: '重命名',
command: 'rename',
svgName: 'dv-rename'
},
{
label: '删除',
command: 'delete',
svgName: 'dv-delete',
divided: true
}
],
folderMenuList: [
{
label: '移动到',
@ -99,7 +73,6 @@ const state = reactive({
divided: true
}
],
resourceTypeList: [],
templateCreatePid: 0
})
@ -107,7 +80,10 @@ const dvSvgType = computed(() =>
curCanvasType.value === 'dashboard' ? 'dv-dashboard-spine' : 'dv-screen-spine'
)
state.resourceTypeList = [
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const resourceTypeList = computed(() => {
const list = [
{
label: '空白新建',
svgName: dvSvgType.value,
@ -117,15 +93,64 @@ state.resourceTypeList = [
label: '使用模板新建',
svgName: 'dv-use-template',
command: 'newFromTemplate'
},
{
}
]
const del = {
label: '新建文件夹',
divided: true,
svgName: 'dv-folder',
command: 'newFolder'
}
if (isDataEaseBi.value) {
del.divided = false
return [del]
}
return [...list, del]
})
const menuList = computed(() => {
const list = [
{
label: '移动到',
command: 'move',
svgName: 'dv-move'
},
{
label: '重命名',
command: 'rename',
svgName: 'dv-rename'
},
{
label: '删除',
command: 'delete',
svgName: 'dv-delete',
divided: true
}
]
const edit = [
{
label: '编辑',
command: 'edit',
svgName: 'dv-edit'
},
{
label: '复制',
command: 'copy',
svgName: 'dv-copy-dark'
}
]
if (isDataEaseBi.value) {
return list
}
return [...list, ...edit]
})
const { dvId } = window.DataEaseBi || router.currentRoute.value.query
if (dvId) {
selectedNodeKey.value = dvId
@ -359,14 +384,19 @@ defineExpose({
<el-tooltip content="新建文件夹" placement="top" effect="dark">
<el-icon
class="custom-icon btn"
style="margin-right: 20px"
:style="{ marginRight: isDataEaseBi ? 0 : '20px' }"
@click="addOperation('newFolder', null, 'folder')"
>
<Icon name="dv-new-folder" />
</el-icon>
</el-tooltip>
<el-tooltip :content="newResourceLabel" placement="top" effect="dark">
<el-tooltip
v-if="!isDataEaseBi"
:content="newResourceLabel"
placement="top"
effect="dark"
>
<el-dropdown popper-class="menu-outer-dv_popper" trigger="hover">
<el-icon class="custom-icon btn" @click="addOperation('newLeaf', null, 'leaf', true)">
<Icon name="icon_file-add_outlined" />
@ -438,7 +468,7 @@ defineExpose({
>
<el-icon
v-on:click.stop
v-if="data.leaf"
v-if="data.leaf && !isDataEaseBi"
class="hover-icon"
@click="resourceEdit(data.id)"
>
@ -448,7 +478,7 @@ defineExpose({
@handle-command="
cmd => addOperation(cmd, data, cmd === 'newFolder' ? 'folder' : 'leaf')
"
:menu-list="state.resourceTypeList"
:menu-list="resourceTypeList"
icon-name="icon_add_outlined"
placement="bottom-start"
v-if="!data.leaf"
@ -458,7 +488,7 @@ defineExpose({
:node="data"
:any-manage="anyManage"
:resource-type="curCanvasType"
:menu-list="data.leaf ? state.menuList : state.folderMenuList"
:menu-list="data.leaf ? menuList : state.folderMenuList"
></dv-handle-more>
</div>
</span>

View File

@ -6,6 +6,7 @@ import DePreview from '@/components/data-visualization/canvas/DePreview.vue'
import PreviewHead from '@/views/data-visualization/PreviewHead.vue'
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
import { initCanvasData, initCanvasDataPrepare } from '@/utils/canvasUtils'
import { useAppStoreWithOut } from '@/store/modules/app'
import { useRequestStoreWithOut } from '@/store/modules/request'
import { usePermissionStoreWithOut } from '@/store/modules/permission'
import { useMoveLine } from '@/hooks/web/useMoveLine'
@ -18,6 +19,7 @@ const dashboardPreview = ref(null)
const slideShow = ref(true)
const requestStore = useRequestStoreWithOut()
const permissionStore = usePermissionStoreWithOut()
const appStore = useAppStoreWithOut()
const dataInitState = ref(true)
const downloadStatus = ref(false)
const state = reactive({
@ -45,6 +47,7 @@ const resourceTreeRef = ref()
const hasTreeData = computed(() => {
return resourceTreeRef.value?.hasData
})
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const rootManage = computed(() => {
return resourceTreeRef.value?.rootManage
@ -190,7 +193,7 @@ defineExpose({
</template>
<template v-else>
<empty-background description="暂无仪表板" img-type="none">
<el-button v-if="rootManage" @click="createNew" type="primary">
<el-button v-if="rootManage && !isDataEaseBi" @click="createNew" type="primary">
<template #icon>
<Icon name="icon_add_outlined" />
</template>

View File

@ -2,11 +2,13 @@
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { useI18n } from '@/hooks/web/useI18n'
import { useAppStoreWithOut } from '@/store/modules/app'
import DvDetailInfo from '@/views/common/DvDetailInfo.vue'
import { storeApi, storeStatusApi } from '@/api/visualization/dataVisualization'
import { ref, watch } from 'vue'
import { ref, watch, computed } from 'vue'
import { XpackComponent } from '@/components/plugin'
const dvMainStore = dvMainStoreWithOut()
const appStore = useAppStoreWithOut()
const { dvInfo } = storeToRefs(dvMainStore)
const emit = defineEmits(['reload', 'download', 'downloadAsAppTemplate'])
const { t } = useI18n()
@ -16,6 +18,7 @@ const preview = () => {
const url = '#/preview?dvId=' + dvInfo.value.id
window.open(url, '_blank')
}
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const reload = () => {
emit('reload', dvInfo.value.id)
@ -85,7 +88,7 @@ watch(
</el-popover>
</div>
<div class="canvas-opt-button">
<el-button @click="preview()">
<el-button v-if="!isDataEaseBi" @click="preview()">
<template #icon>
<icon name="icon_pc_outlined"></icon>
</template>
@ -97,7 +100,12 @@ watch(
:weight="dvInfo.weight"
:resource-type="dvInfo.type"
/>
<el-button class="custom-button" v-if="dvInfo.weight > 6" type="primary" @click="dvEdit()">
<el-button
class="custom-button"
v-if="dvInfo.weight > 6 && !isDataEaseBi"
type="primary"
@click="dvEdit()"
>
<template #icon>
<icon name="icon_edit_outlined"></icon>
</template>

View File

@ -6,6 +6,7 @@ import DePreview from '@/components/data-visualization/canvas/DePreview.vue'
import PreviewHead from '@/views/data-visualization/PreviewHead.vue'
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
import { storeToRefs } from 'pinia'
import { useAppStoreWithOut } from '@/store/modules/app'
import { initCanvasData } from '@/utils/canvasUtils'
import { useRequestStoreWithOut } from '@/store/modules/request'
import { usePermissionStoreWithOut } from '@/store/modules/permission'
@ -41,6 +42,9 @@ const hasTreeData = computed(() => {
const rootManage = computed(() => {
return resourceTreeRef.value?.rootManage
})
const appStore = useAppStoreWithOut()
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
function createNew() {
resourceTreeRef.value?.createNewObject()
@ -173,7 +177,7 @@ onBeforeMount(() => {
</template>
<template v-else>
<empty-background description="暂无数据大屏" img-type="none">
<el-button v-if="rootManage" @click="createNew" type="primary">
<el-button v-if="rootManage && !isDataEaseBi" @click="createNew" type="primary">
<template #icon>
<Icon name="icon_add_outlined" />
</template>

View File

@ -23,6 +23,7 @@ import { guid } from '@/views/visualized/data/dataset/form/util'
import { save } from '@/api/visualization/dataVisualization'
import { cloneDeep } from 'lodash-es'
import { fieldType } from '@/utils/attr'
import { useAppStoreWithOut } from '@/store/modules/app'
import {
DEFAULT_CANVAS_STYLE_DATA_LIGHT,
@ -50,6 +51,7 @@ interface Node {
createTime: number
weight: number
}
const appStore = useAppStoreWithOut()
const rootManage = ref(false)
const nickName = ref('')
const router = useRouter()
@ -62,6 +64,7 @@ const state = reactive({
const resourceGroupOpt = ref()
const curCanvasType = ref('')
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const createPanel = path => {
const baseUrl = `#/${path}?opt=create&id=${nodeInfo.id}`
window.open(baseUrl, '_blank')
@ -401,7 +404,8 @@ const nodeCollapse = data => {
}
}
const datasetTypeList = [
const datasetTypeList = computed(() => {
const list = [
{
label: '新建数据集',
svgName: 'icon_dataset',
@ -414,6 +418,12 @@ const datasetTypeList = [
command: 'folder'
}
]
if (isDataEaseBi.value) {
list.shift()
list[0].divided = false
}
return list
})
const defaultProps = {
children: 'children',
@ -449,7 +459,7 @@ const filterNode = (value: string, data: BusiTreeNode) => {
}
const getMenuList = (val: boolean) => {
return !val
return !val || isDataEaseBi.value
? menuList
: [
{
@ -477,13 +487,19 @@ const getMenuList = (val: boolean) => {
>
<el-icon
class="custom-icon btn"
style="margin-right: 20px"
:style="{ marginRight: isDataEaseBi ? 0 : '20px' }"
@click="handleDatasetTree('folder')"
>
<Icon name="dv-new-folder" />
</el-icon>
</el-tooltip>
<el-tooltip class="box-item" effect="dark" content="新建数据集" placement="top">
<el-tooltip
v-if="!isDataEaseBi"
class="box-item"
effect="dark"
content="新建数据集"
placement="top"
>
<el-icon class="custom-icon btn" @click="createDataset">
<Icon name="icon_file-add_outlined" />
</el-icon>
@ -537,7 +553,11 @@ const getMenuList = (val: boolean) => {
placement="bottom-start"
v-if="!data.leaf"
></handle-more>
<el-icon class="hover-icon" @click.stop="handleEdit(data.id)" v-else>
<el-icon
v-else-if="!isDataEaseBi"
class="hover-icon"
@click.stop="handleEdit(data.id)"
>
<icon name="icon_edit_outlined"></icon>
</el-icon>
<handle-more
@ -552,10 +572,14 @@ const getMenuList = (val: boolean) => {
</div>
</el-aside>
<div class="dataset-content">
<div class="dataset-content" :class="isDataEaseBi && 'h100'">
<template v-if="!state.datasetTree.length">
<empty-background description="暂无数据集" img-type="none">
<el-button v-if="rootManage" @click="() => createDataset()" type="primary">
<el-button
v-if="rootManage && !isDataEaseBi"
@click="() => createDataset()"
type="primary"
>
<template #icon>
<Icon name="icon_add_outlined"></Icon>
</template>
@ -583,7 +607,7 @@ const getMenuList = (val: boolean) => {
:creator="infoList.creator"
></dataset-detail>
</el-popover>
<div class="right-btn">
<div v-if="!isDataEaseBi" class="right-btn">
<el-button secondary @click="createPanel('dashboard')" v-permission="['panel']">
<template #icon>
<Icon name="icon_dashboard_outlined"></Icon>
@ -735,6 +759,10 @@ const getMenuList = (val: boolean) => {
height: calc(100vh - 56px);
overflow: auto;
position: relative;
&.h100 {
height: 100%;
}
}
.dataset-content {

View File

@ -17,6 +17,7 @@ import DatasetDetail from '@/views/visualized/data/dataset/DatasetDetail.vue'
import { timestampFormatDate } from '@/views/visualized/data/dataset/form/util'
import EmptyBackground from '@/components/empty-background/src/EmptyBackground.vue'
import dayjs from 'dayjs'
import { useAppStoreWithOut } from '@/store/modules/app'
import {
getTableField,
listDatasourceTables,
@ -67,6 +68,7 @@ export interface Node {
const { t } = useI18n()
const router = useRouter()
const appStore = useAppStoreWithOut()
const state = reactive({
datasourceTree: [] as BusiTreeNode[],
dsTableData: [],
@ -85,6 +87,7 @@ const recordState = reactive({
total: 0
}
})
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
const createDataset = (tableName?: string) => {
router.push({
@ -134,7 +137,8 @@ const typeMap = dsTypes.reduce((pre, next) => {
return pre
}, {})
const datasetTypeList = [
const datasetTypeList = computed(() => {
const list = [
{
label: '新建数据源',
svgName: 'icon_dataset',
@ -147,6 +151,12 @@ const datasetTypeList = [
command: 'folder'
}
]
if (isDataEaseBi.value) {
list.shift()
list[0].divided = false
}
return list
})
const dsTableDataLoading = ref(false)
const selectDataset = row => {
@ -652,7 +662,7 @@ onMounted(() => {
})
const getMenuList = (val: boolean) => {
return !val
return !val || isDataEaseBi.value
? menuList
: [
{
@ -675,13 +685,18 @@ const getMenuList = (val: boolean) => {
<el-tooltip effect="dark" content="新建文件夹" placement="top">
<el-icon
class="custom-icon btn"
style="margin-right: 20px"
:style="{ marginRight: isDataEaseBi ? 0 : '20px' }"
@click="handleDatasourceTree('folder')"
>
<Icon name="dv-new-folder" />
</el-icon>
</el-tooltip>
<el-tooltip effect="dark" :content="t('datasource.create')" placement="top">
<el-tooltip
v-if="!isDataEaseBi"
effect="dark"
:content="t('datasource.create')"
placement="top"
>
<el-icon class="custom-icon btn" @click="createDatasource">
<Icon name="icon_file-add_outlined" />
</el-icon>
@ -739,7 +754,7 @@ const getMenuList = (val: boolean) => {
<el-icon
class="hover-icon"
@click.stop="handleEdit(data)"
v-else-if="data.type !== 'Excel'"
v-else-if="data.type !== 'Excel' && !isDataEaseBi"
>
<icon name="icon_edit_outlined"></icon>
</el-icon>
@ -757,10 +772,14 @@ const getMenuList = (val: boolean) => {
</div>
</el-aside>
<div class="datasource-content">
<div class="datasource-content" :class="isDataEaseBi && 'h100'">
<template v-if="!state.datasourceTree.length">
<empty-background description="暂无数据源" img-type="none">
<el-button v-if="rootManage" @click="() => createDatasource()" type="primary">
<el-button
v-if="rootManage && !isDataEaseBi"
@click="() => createDatasource()"
type="primary"
>
<template #icon>
<Icon name="icon_add_outlined"></Icon>
</template>
@ -792,7 +811,7 @@ const getMenuList = (val: boolean) => {
:creator="infoList.creator"
></dataset-detail>
</el-popover>
<div class="right-btn flex-align-center">
<div class="right-btn flex-align-center" v-if="!isDataEaseBi">
<el-button secondary @click="createDataset(null)" v-permission="['dataset']">
<template #icon>
<Icon name="icon_dataset_outlined"></Icon>
@ -938,7 +957,12 @@ const getMenuList = (val: boolean) => {
width="108"
>
<template #default="scope">
<el-tooltip effect="dark" content="新建数据集" placement="top">
<el-tooltip
v-if="!isDataEaseBi"
effect="dark"
content="新建数据集"
placement="top"
>
<el-button
@click.stop="createDataset(scope.row.name)"
text
@ -1541,6 +1565,13 @@ const getMenuList = (val: boolean) => {
height: calc(100vh - 56px);
overflow: auto;
position: relative;
&.h100 {
height: 100%;
.datasource-table {
height: calc(100% - 140px);
}
}
}
.datasource-list {

View File

@ -7,7 +7,7 @@ import { defineConfig, mergeConfig } from 'vite'
export default defineConfig(({mode}) => {
if (mode === 'dev') {
return mergeConfig(common , {...dev, ...pages})
return mergeConfig(common , mergeConfig(dev, pages))
}
if (mode === 'lib') {