<script setup lang="ts">
|
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
import DeResourceTree from '@/views/common/DeResourceTree.vue'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import ArrowSide from '@/views/common/DeResourceArrow.vue'
|
import { nextTick, onBeforeMount, reactive, ref, computed, onMounted } from '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 {
|
getMapElementIds,
|
initCanvasData,
|
initCanvasDataPrepare,
|
onInitReady
|
} from '@/utils/canvasUtils'
|
import { useMoveLine } from '@/hooks/web/useMoveLine'
|
import { Icon } from '@/components/icon-custom'
|
import { download2AppTemplate, downloadCanvas2 } from '@/utils/imgUtils'
|
import MultiplexPreviewShow from '@/views/data-visualization/MultiplexPreviewShow.vue'
|
import DvPreview from '@/views/data-visualization/DvPreview.vue'
|
import AppExportForm from '@/components/de-app/AppExportForm.vue'
|
import { ElMessage } from 'element-plus-secondary'
|
import { useEmitt } from '@/hooks/web/useEmitt'
|
|
import { useUserStoreWithOut } from '@/store/modules/user'
|
import { useI18n } from '@/hooks/web/useI18n'
|
import {
|
exportLogApp,
|
exportLogImg,
|
exportLogPDF,
|
exportLogTemplate
|
} from '@/api/visualization/dataVisualization'
|
import { deepCopy } from '@/utils/utils'
|
const userStore = useUserStoreWithOut()
|
|
const userName = computed(() => userStore.getName)
|
const { t } = useI18n()
|
|
const dvMainStore = dvMainStoreWithOut()
|
const { dvInfo, canvasViewDataInfo } = storeToRefs(dvMainStore)
|
const previewCanvasContainer = ref(null)
|
const dvPreviewRef = ref(null)
|
const slideShow = ref(true)
|
const dataInitState = ref(true)
|
const downloadStatus = ref(false)
|
const { width, node } = useMoveLine('DASHBOARD')
|
const appExportFormRef = ref(null)
|
const props = defineProps({
|
showPosition: {
|
required: false,
|
type: String,
|
default: 'preview'
|
},
|
noClose: {
|
required: false,
|
type: Boolean,
|
default: false
|
},
|
resourceTable: {
|
required: false,
|
type: String,
|
default: 'core'
|
}
|
})
|
|
const resourceTreeRef = ref()
|
|
const hasTreeData = computed(() => {
|
return resourceTreeRef.value?.hasData
|
})
|
|
const mounted = computed(() => {
|
return resourceTreeRef.value?.mounted
|
})
|
|
const rootManage = computed(() => {
|
return resourceTreeRef.value?.rootManage
|
})
|
const appStore = useAppStoreWithOut()
|
|
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
|
function createNew() {
|
resourceTreeRef.value?.createNewObject()
|
}
|
|
const loadCanvasData = (dvId, weight?, ext?) => {
|
const initMethod = props.showPosition === 'multiplexing' ? initCanvasDataPrepare : initCanvasData
|
dataInitState.value = false
|
initMethod(
|
dvId,
|
{ busiFlag: 'dataV', resourceTable: 'core' },
|
function ({
|
canvasDataResult,
|
canvasStyleResult,
|
dvInfo,
|
canvasViewInfoPreview,
|
curPreviewGap
|
}) {
|
dvInfo['weight'] = weight
|
dvInfo['ext'] = ext || 0
|
state.canvasDataPreview = canvasDataResult
|
state.canvasStylePreview = canvasStyleResult
|
state.canvasViewInfoPreview = canvasViewInfoPreview
|
state.dvInfo = dvInfo
|
state.curPreviewGap = curPreviewGap
|
dataInitState.value = true
|
// 修复铺满全屏模版导出错位问题
|
if (props.showPosition !== 'multiplexing') {
|
state.canvasDataPreviewSource = deepCopy(canvasDataResult)
|
state.canvasStylePreviewSource = deepCopy(canvasStyleResult)
|
}
|
|
if (props.showPosition === 'preview') {
|
dvMainStore.updateCurDvInfo(dvInfo)
|
nextTick(() => {
|
dvPreviewRef.value?.restore()
|
})
|
}
|
nextTick(() => {
|
onInitReady({ resourceId: dvId })
|
})
|
}
|
)
|
}
|
const download = type => {
|
downloadStatus.value = true
|
const mapElementIds = getMapElementIds(state.canvasDataPreview)
|
mapElementIds.forEach(id => useEmitt().emitter.emit('l7-prepare-picture', id))
|
setTimeout(() => {
|
const vueDom = previewCanvasContainer.value.querySelector('.canvas-container')
|
downloadCanvas2(type, vueDom, state.dvInfo.name, () => {
|
downloadStatus.value = false
|
const param = {
|
id: state.dvInfo.id,
|
type: state.dvInfo.type === 'dashboard' ? 'panel' : 'screen'
|
}
|
type === 'img' ? exportLogImg(param) : exportLogPDF(param)
|
mapElementIds.forEach(id => useEmitt().emitter.emit('l7-unprepare-picture', id))
|
})
|
}, 200)
|
}
|
const fileDownload = (downloadType, attachParams) => {
|
downloadStatus.value = true
|
const mapElementIds = getMapElementIds(state.canvasDataPreview)
|
mapElementIds.forEach(id => useEmitt().emitter.emit('l7-prepare-picture', id))
|
setTimeout(() => {
|
const vueDom = previewCanvasContainer.value.querySelector('.canvas-container')
|
download2AppTemplate(downloadType, vueDom, state.dvInfo.name, attachParams, () => {
|
downloadStatus.value = false
|
const param = {
|
id: state.dvInfo.id,
|
type: state.dvInfo.type === 'dashboard' ? 'panel' : 'screen'
|
}
|
downloadType === 'app' ? exportLogApp(param) : exportLogTemplate(param)
|
mapElementIds.forEach(id => useEmitt().emitter.emit('l7-unprepare-picture', id))
|
})
|
}, 1000)
|
}
|
|
const downloadAsAppTemplate = downloadType => {
|
if (downloadType === 'template') {
|
fileDownload(downloadType, null)
|
} else if (downloadType === 'app') {
|
downLoadToAppPre()
|
}
|
}
|
|
const downLoadToAppPre = () => {
|
const result = checkTemplate()
|
if (result && result.length > 0) {
|
ElMessage.warning(`当前仪表板中[${result}]属于模版图表,无法导出,请先设置数据集!`)
|
} else {
|
appExportFormRef.value.init({
|
appName: state.dvInfo.name,
|
icon: null,
|
version: '2.0',
|
creator: userName.value,
|
required: '2.9.0',
|
description: null
|
})
|
}
|
}
|
const checkTemplate = () => {
|
let templateViewNames = ','
|
Object.keys(canvasViewDataInfo.value).forEach(key => {
|
const viewInfo = canvasViewDataInfo.value[key]
|
if (viewInfo && viewInfo?.dataFrom === 'template') {
|
templateViewNames = templateViewNames + viewInfo.title + ','
|
}
|
})
|
return templateViewNames.slice(1)
|
}
|
|
const slideOpenChange = () => {
|
slideShow.value = !slideShow.value
|
}
|
|
const reload = id => {
|
loadCanvasData(id, state.dvInfo.weight, state.dvInfo.ext)
|
}
|
|
const resourceNodeClick = data => {
|
loadCanvasData(data.id, data.weight, data.ext)
|
}
|
|
const dataVKeepSize = computed(() => {
|
return state.canvasStylePreview?.screenAdaptor === 'keep'
|
})
|
|
const state = reactive({
|
canvasDataPreviewSource: null,
|
canvasStylePreviewSource: null,
|
canvasDataPreview: null,
|
canvasStylePreview: null,
|
canvasViewInfoPreview: null,
|
dvInfo: null,
|
curPreviewGap: 0
|
})
|
|
const sideTreeStatus = ref(true)
|
const changeSideTreeStatus = val => {
|
sideTreeStatus.value = val
|
}
|
|
const mouseenter = () => {
|
appStore.setArrowSide(true)
|
}
|
|
const mouseleave = () => {
|
appStore.setArrowSide(false)
|
}
|
|
const getPreviewStateInfo = () => {
|
return state
|
}
|
|
const downLoadApp = appAttachInfo => {
|
fileDownload('app', appAttachInfo)
|
}
|
|
onMounted(() => {
|
useEmitt({
|
name: 'canvasDownload',
|
callback: function () {
|
download('img')
|
}
|
})
|
})
|
|
defineExpose({
|
getPreviewStateInfo
|
})
|
|
onBeforeMount(() => {
|
if (props.showPosition === 'preview') {
|
dvMainStore.canvasDataInit()
|
}
|
})
|
</script>
|
|
<template>
|
<div class="dv-preview">
|
<ArrowSide
|
v-if="!noClose"
|
:style="{ left: (sideTreeStatus ? width - 12 : 0) + 'px' }"
|
@change-side-tree-status="changeSideTreeStatus"
|
:isInside="!sideTreeStatus"
|
></ArrowSide>
|
<el-aside
|
class="resource-area"
|
@mouseenter="mouseenter"
|
@mouseleave="mouseleave"
|
:class="{ 'close-side': !slideShow, retract: !sideTreeStatus }"
|
ref="node"
|
:style="{ width: width + 'px' }"
|
>
|
<ArrowSide
|
v-if="!noClose"
|
:isInside="!sideTreeStatus"
|
:style="{ left: (sideTreeStatus ? width - 12 : 0) + 'px' }"
|
@change-side-tree-status="changeSideTreeStatus"
|
></ArrowSide>
|
<de-resource-tree
|
ref="resourceTreeRef"
|
v-show="slideShow"
|
:cur-canvas-type="'dataV'"
|
:show-position="showPosition"
|
:resource-table="resourceTable"
|
@node-click="resourceNodeClick"
|
/>
|
</el-aside>
|
<el-container
|
class="preview-area"
|
:class="{ 'no-data': !state.dvInfo?.id }"
|
v-loading="!dataInitState"
|
>
|
<div @click="slideOpenChange" class="flexible-button-area" v-if="false">
|
<el-icon v-if="slideShow"><ArrowLeft /></el-icon>
|
<el-icon v-else><ArrowRight /></el-icon>
|
</div>
|
<template v-if="dvInfo.name">
|
<preview-head
|
v-if="showPosition === 'preview'"
|
@reload="reload"
|
@download="download"
|
@downloadAsAppTemplate="downloadAsAppTemplate"
|
/>
|
<div
|
v-if="showPosition === 'multiplexing' && dataInitState"
|
class="content multiplexing-content"
|
>
|
<multiplex-preview-show
|
:component-data="state.canvasDataPreview"
|
:canvas-style-data="state.canvasStylePreview"
|
:canvas-view-info="state.canvasViewInfoPreview"
|
:dv-info="state.dvInfo"
|
></multiplex-preview-show>
|
</div>
|
<div
|
v-if="showPosition === 'preview'"
|
:class="{ 'canvas_keep-size': dataVKeepSize }"
|
ref="previewCanvasContainer"
|
class="content"
|
>
|
<dv-preview
|
ref="dvPreviewRef"
|
v-if="state.canvasStylePreview && dataInitState"
|
:show-position="showPosition"
|
:canvas-data-preview="state.canvasDataPreview"
|
:canvas-style-preview="state.canvasStylePreview"
|
:canvas-view-info-preview="state.canvasViewInfoPreview"
|
:dv-info="state.dvInfo"
|
:cur-preview-gap="state.curPreviewGap"
|
:download-status="downloadStatus"
|
></dv-preview>
|
</div>
|
</template>
|
<template v-else-if="hasTreeData && mounted">
|
<empty-background
|
v-if="dataInitState"
|
:description="t('visualization.select_screen_tips')"
|
img-type="select"
|
/>
|
</template>
|
<template v-else-if="mounted">
|
<empty-background
|
v-if="dataInitState"
|
:description="t('visualization.no_screen')"
|
img-type="none"
|
>
|
<el-button v-if="rootManage && !isDataEaseBi" @click="createNew" type="primary">
|
<template #icon>
|
<Icon name="icon_add_outlined"><icon_add_outlined class="svg-icon" /></Icon>
|
</template>
|
{{ t('commons.create') }}{{ t('work_branch.big_data_screen') }}
|
</el-button>
|
</empty-background>
|
</template>
|
</el-container>
|
</div>
|
<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">
|
.dv-preview {
|
width: 100%;
|
height: 100%;
|
overflow: hidden;
|
display: flex;
|
background: #ffffff;
|
position: relative;
|
.resource-area {
|
position: relative;
|
height: 100%;
|
width: 279px;
|
padding: 0;
|
overflow: visible;
|
border-right: 1px solid #d7d7d7;
|
|
&.retract {
|
display: none;
|
}
|
}
|
.preview-area {
|
flex: 1;
|
display: flex;
|
flex-direction: column;
|
overflow-x: hidden;
|
overflow-y: auto;
|
position: relative;
|
//transition: 0.5s;
|
|
&.no-data {
|
background-color: rgba(245, 246, 247, 1);
|
}
|
|
.content {
|
flex: 1;
|
width: 100%;
|
overflow-x: hidden;
|
overflow-y: auto;
|
align-items: center;
|
}
|
}
|
}
|
|
.close-side {
|
width: 0px !important;
|
padding: 0px !important;
|
border-right: 0px !important;
|
}
|
|
.flexible-button-area {
|
position: absolute;
|
height: 60px;
|
width: 16px;
|
left: 0;
|
top: calc(50% - 30px);
|
background-color: #ffffff;
|
border-radius: 0 4px 4px 0;
|
cursor: pointer;
|
z-index: 10;
|
display: flex;
|
align-items: center;
|
border-top: 1px solid #d7d7d7;
|
border-right: 1px solid #d7d7d7;
|
border-bottom: 1px solid #d7d7d7;
|
}
|
|
.multiplexing-content {
|
padding: 12px;
|
background-color: rgb(245, 246, 247);
|
}
|
</style>
|