|
|
<template>
|
|
|
<div
|
|
|
v-if="hasPermission"
|
|
|
class="bs-page-design-wrap"
|
|
|
>
|
|
|
<PageTopSetting
|
|
|
v-show="headerShow"
|
|
|
ref="PageTopSetting"
|
|
|
:right-fold="rightVisiable"
|
|
|
@updateRightVisiable="updateRightVisiable"
|
|
|
@showPageInfo="showPageInfo"
|
|
|
@empty="empty"
|
|
|
/>
|
|
|
<div class="drag-wrap">
|
|
|
<!-- 左侧面板 -->
|
|
|
<LeftPanel
|
|
|
:header-show="headerShow"
|
|
|
:height="height"
|
|
|
@openRightPanel="openRightPanel"
|
|
|
@openResource="initDialog"
|
|
|
@openComponent="openComponent"
|
|
|
@toggleLeftSidebar="toggleLeftSidebar"
|
|
|
/>
|
|
|
<!-- 中间组件展示面板 -->
|
|
|
<div
|
|
|
v-loading="pageLoading"
|
|
|
class="grid-wrap-box"
|
|
|
:style="{
|
|
|
height: 'calc(100vh - 48px)'
|
|
|
}"
|
|
|
tabindex="1000"
|
|
|
@keydown="designKeydown"
|
|
|
>
|
|
|
<SketchDesignRuler
|
|
|
ref="Rules"
|
|
|
:width="3000"
|
|
|
:height="3000"
|
|
|
:page-width="pageConfig.w"
|
|
|
:page-height="pageConfig.h"
|
|
|
@changeStart="changeStart"
|
|
|
>
|
|
|
<MouseSelect
|
|
|
:offset-x="offset.x"
|
|
|
:offset-y="offset.y"
|
|
|
@selectArea="onSelectArea"
|
|
|
>
|
|
|
<Render
|
|
|
ref="Render"
|
|
|
:class="{
|
|
|
'grid-bg': hasGrid
|
|
|
}"
|
|
|
@openRightPanel="openRightPanel"
|
|
|
/>
|
|
|
</MouseSelect>
|
|
|
</SketchDesignRuler>
|
|
|
<div class="footer-tools-bar">
|
|
|
<el-slider
|
|
|
class="bs-slider-wrap"
|
|
|
:value="zoom"
|
|
|
:min="10"
|
|
|
style="width: 200px; margin-right: 20px"
|
|
|
@input="changeScreenZoom"
|
|
|
/>
|
|
|
<span class="select-zoom-text">缩放比例</span>
|
|
|
<el-select
|
|
|
class="bs-el-select"
|
|
|
popper-class="bs-el-select"
|
|
|
:value="zoom"
|
|
|
@change="changeScreenZoom"
|
|
|
>
|
|
|
<el-option
|
|
|
v-for="(zoom,index) in zoomList"
|
|
|
:key="index"
|
|
|
:label="zoom.label"
|
|
|
:value="zoom.value"
|
|
|
/>
|
|
|
</el-select>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 右侧折叠设置面板 -->
|
|
|
<SettingPanel
|
|
|
:header-show="headerShow"
|
|
|
:height="height"
|
|
|
:right-visiable.sync="rightVisiable"
|
|
|
:page-info-visiable="pageInfoVisiable"
|
|
|
@updateSetting="updateSetting"
|
|
|
@updateDataSetting="updateDataSetting"
|
|
|
@updatePage="updatePage"
|
|
|
>
|
|
|
<template #dataSetSelect="{ value }">
|
|
|
<slot
|
|
|
name="dataSetSelect"
|
|
|
:value="value"
|
|
|
/>
|
|
|
</template>
|
|
|
</SettingPanel>
|
|
|
<!-- 添加资源面板 -->
|
|
|
<SourceDialog
|
|
|
ref="SourceDialog"
|
|
|
@getImg="setImg"
|
|
|
/>
|
|
|
<ComponentDialog
|
|
|
ref="componentDialog"
|
|
|
@setComponent="setComponent"
|
|
|
@setRemoteComponent="setRemoteComponent"
|
|
|
/>
|
|
|
<iframe-dialog
|
|
|
v-if="iframeDialog"
|
|
|
ref="iframeDialog"
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
<NotPermission v-else-if="!hasPermission" />
|
|
|
</template>
|
|
|
<script>
|
|
|
import SourceDialog from './SourceDialog/index.vue'
|
|
|
import ComponentDialog from './ComponentDialog/index.vue'
|
|
|
import iframeDialog from 'data-room-ui/BasicComponents/LinkChart/iframeDialog'
|
|
|
import {
|
|
|
dataConfig,
|
|
|
settingConfig
|
|
|
} from 'data-room-ui/BasicComponents/Picture/settingConfig'
|
|
|
import LeftPanel from './LeftPanel.vue'
|
|
|
import SettingPanel from './SettingPanel.vue'
|
|
|
import PageTopSetting from './PageDesignTop.vue'
|
|
|
import Render from '../Render'
|
|
|
import { mapActions, mapMutations, mapState } from 'vuex'
|
|
|
import SketchDesignRuler from 'data-room-ui/BigScreenDesign/RulerTool/SketchRuler.vue'
|
|
|
import { G2 } from '@antv/g2plot'
|
|
|
import multipleSelectMixin from 'data-room-ui/js/mixins/multipleSelectMixin'
|
|
|
import { getThemeConfig, getScreenInfo } from 'data-room-ui/js/api/bigScreenApi'
|
|
|
import MouseSelect from './MouseSelect/index.vue'
|
|
|
import _ from 'lodash'
|
|
|
import { randomString } from '../js/utils'
|
|
|
import { isFirefox } from 'data-room-ui/js/utils/userAgent'
|
|
|
import { handleResData } from 'data-room-ui/js/store/actions.js'
|
|
|
import { EventBus } from 'data-room-ui/js/utils/eventBus'
|
|
|
import NotPermission from 'data-room-ui/NotPermission'
|
|
|
export default {
|
|
|
name: 'BigScreenDesign',
|
|
|
components: {
|
|
|
PageTopSetting,
|
|
|
LeftPanel,
|
|
|
Render,
|
|
|
SketchDesignRuler,
|
|
|
MouseSelect,
|
|
|
SettingPanel,
|
|
|
SourceDialog,
|
|
|
ComponentDialog,
|
|
|
iframeDialog,
|
|
|
NotPermission
|
|
|
},
|
|
|
mixins: [multipleSelectMixin],
|
|
|
props: {
|
|
|
code: {
|
|
|
type: String,
|
|
|
default: ''
|
|
|
},
|
|
|
headerShow: {
|
|
|
type: Boolean,
|
|
|
default: true
|
|
|
},
|
|
|
height: {
|
|
|
type: String,
|
|
|
default: 'calc(100vh - 40px)'
|
|
|
}
|
|
|
},
|
|
|
data () {
|
|
|
return {
|
|
|
hasPermission: true,
|
|
|
rightVisiable: false,
|
|
|
pageInfoVisiable: false,
|
|
|
ruleStartX: 100,
|
|
|
ruleStartY: 100,
|
|
|
zoomList: [
|
|
|
{
|
|
|
label: '自适应',
|
|
|
value: 'auto'
|
|
|
},
|
|
|
{
|
|
|
label: '100%',
|
|
|
value: 100
|
|
|
},
|
|
|
{
|
|
|
label: '80%',
|
|
|
value: 80
|
|
|
},
|
|
|
{
|
|
|
label: '50%',
|
|
|
value: 50
|
|
|
},
|
|
|
{
|
|
|
label: '20%',
|
|
|
value: 20
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
},
|
|
|
watch: {
|
|
|
fitZoom (zoom) {
|
|
|
this.zoomList[0] = {
|
|
|
label: `自适应(${zoom}%)`,
|
|
|
value: zoom
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
...mapState({
|
|
|
pageInfo: (state) => state.bigScreen.pageInfo,
|
|
|
chartList: (state) => state.bigScreen.pageInfo.chartList,
|
|
|
pageConfig: (state) => state.bigScreen.pageInfo.pageConfig,
|
|
|
pageLoading: (state) => state.bigScreen.pageLoading,
|
|
|
hoverCode: (state) => state.bigScreen.hoverCode,
|
|
|
presetLine: (state) => state.bigScreen.presetLine,
|
|
|
updateKey: (state) => state.bigScreen.updateKey,
|
|
|
hasGrid: (state) => state.bigScreen.hasGrid,
|
|
|
zoom: (state) => state.bigScreen.zoom,
|
|
|
fitZoom: (state) => state.bigScreen.fitZoom,
|
|
|
iframeDialog: (state) => state.bigScreen.iframeDialog
|
|
|
}),
|
|
|
pageCode () {
|
|
|
return this.code || this.$route.query.code
|
|
|
},
|
|
|
offset () {
|
|
|
return {
|
|
|
x: 220 + 50 - this.ruleStartX,
|
|
|
y: 55 + 50 - this.ruleStartY
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
// beforeRouteEnter (to, from, next) {
|
|
|
// // 判断进入设计页面前是否有访问权限
|
|
|
// const code = to.query.code
|
|
|
// get(`/bigScreen/permission/check/${code}`).then((res) => {
|
|
|
// if (res) {
|
|
|
// next((vm) => {
|
|
|
// // 重置大屏的vuex store
|
|
|
// vm.$store.commit('bigScreen/resetStoreData')
|
|
|
// })
|
|
|
// } else {
|
|
|
// next('/notPermission')
|
|
|
// }
|
|
|
// })
|
|
|
// },
|
|
|
created () {
|
|
|
this.changePageLoading(true)
|
|
|
this.permission()
|
|
|
/**
|
|
|
* 以下是为了解决在火狐浏览器上推拽时弹出tab页到搜索问题
|
|
|
* @param event
|
|
|
*/
|
|
|
if (isFirefox()) {
|
|
|
document.body.ondrop = function (event) {
|
|
|
event.preventDefault()
|
|
|
event.stopPropagation()
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
mounted () {
|
|
|
EventBus.$on('closeRightPanel', () => { this.rightVisiable = false })
|
|
|
},
|
|
|
beforeDestroy () {
|
|
|
this.clearTimeline()
|
|
|
EventBus.$off('closeRightPanel')
|
|
|
},
|
|
|
methods: {
|
|
|
...mapActions('bigScreen', ['initLayout']),
|
|
|
...mapMutations('bigScreen', [
|
|
|
'changeLayout',
|
|
|
'changePageLoading',
|
|
|
'resetPresetLine',
|
|
|
'changeActiveCode',
|
|
|
'changeActiveCodes',
|
|
|
'changePageConfig',
|
|
|
'changeChartConfig',
|
|
|
'changeChartKey',
|
|
|
'changeZoom',
|
|
|
'clearTimeline',
|
|
|
'saveTimeLine',
|
|
|
'changeIframeDialog'
|
|
|
]),
|
|
|
// 判断页面权限
|
|
|
permission () {
|
|
|
this.$dataRoomAxios.get(`/bigScreen/permission/check/${this.pageCode}`).then(res => {
|
|
|
this.hasPermission = res
|
|
|
if (res) {
|
|
|
this.init()
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// 添加资源弹窗初始化
|
|
|
initDialog () {
|
|
|
this.$refs.SourceDialog.init()
|
|
|
},
|
|
|
openComponent () {
|
|
|
this.$refs.componentDialog.init()
|
|
|
},
|
|
|
// 从组件库添加组件模板到当前画布
|
|
|
setComponent (component) {
|
|
|
// 根据component获取页面详情
|
|
|
getScreenInfo(component.code).then(res => {
|
|
|
// 给组件库导入的组件加入统一的前缀
|
|
|
const randomStr = randomString(8)
|
|
|
const pageInfo = handleResData(res)
|
|
|
const chartList = pageInfo.chartList.reverse()
|
|
|
chartList.forEach((chart) => {
|
|
|
// 如果组件存在数据联动,则将数据联动的code也加上相同的前缀
|
|
|
if (chart.linkage && chart.linkage.components && chart.linkage.components.length) {
|
|
|
chart.linkage.components.forEach((com) => { com.componentKey = randomStr + com.componentKey })
|
|
|
}
|
|
|
const newChart = {
|
|
|
...chart,
|
|
|
offsetX: 0,
|
|
|
group: randomStr,
|
|
|
code: randomStr + chart.code
|
|
|
}
|
|
|
this.$refs.Render.addChart(newChart, { x: chart.x, y: chart.y }, true)
|
|
|
this.updateRightVisiable(false)
|
|
|
})
|
|
|
})
|
|
|
},
|
|
|
// 添加远程组件
|
|
|
setRemoteComponent (component) {
|
|
|
const newChart = {
|
|
|
...component,
|
|
|
offsetX: 0,
|
|
|
offsetY: 0,
|
|
|
code: randomString(8)
|
|
|
}
|
|
|
this.$refs.Render.addChart(newChart, { x: 0, y: 0 })
|
|
|
},
|
|
|
setImg (val) {
|
|
|
this.$refs.Render.addSourceChart(
|
|
|
JSON.stringify({
|
|
|
title: val.originalName,
|
|
|
name: val.originalName,
|
|
|
icon: null,
|
|
|
className:
|
|
|
'com.gccloud.dataroom.core.module.chart.components.ScreenPictureChart',
|
|
|
w: 300,
|
|
|
h: 300,
|
|
|
x: 0,
|
|
|
y: 0,
|
|
|
type: 'picture',
|
|
|
option: {
|
|
|
..._.cloneDeep(settingConfig)
|
|
|
},
|
|
|
setting: {}, // 右侧面板自定义配置
|
|
|
dataHandler: {}, // 数据自定义处理js脚本
|
|
|
..._.cloneDeep(dataConfig),
|
|
|
customize: {
|
|
|
url: val.url,
|
|
|
radius: 0,
|
|
|
opacity: 100
|
|
|
}
|
|
|
}),
|
|
|
{ x: 150, y: 100 }
|
|
|
)
|
|
|
},
|
|
|
init () {
|
|
|
this.changePageLoading(true)
|
|
|
this.initLayout(this.pageCode)
|
|
|
.then(() => {
|
|
|
const themeName = this.pageConfig.customTheme
|
|
|
if (!['dark', 'light', 'auto'].includes(themeName)) {
|
|
|
getThemeConfig().then((res) => {
|
|
|
// 初始化时如果就是自定义主题则统一注册
|
|
|
const { registerTheme } = G2
|
|
|
registerTheme(themeName, { ...res.chart })
|
|
|
const pageConfig = this.pageConfig
|
|
|
pageConfig.themeJson = res
|
|
|
this.changePageConfig(pageConfig)
|
|
|
this.changePageLoading(false)
|
|
|
})
|
|
|
} else {
|
|
|
this.changePageLoading(false)
|
|
|
}
|
|
|
})
|
|
|
.finally(() => {
|
|
|
setTimeout(() => {
|
|
|
this.resetPresetLine()
|
|
|
}, 500)
|
|
|
})
|
|
|
},
|
|
|
// 点击当前组件时打开右侧面板
|
|
|
openRightPanel (card) {
|
|
|
this.rightVisiable = true
|
|
|
this.pageInfoVisiable = false
|
|
|
},
|
|
|
/**
|
|
|
* @description: 清空页面
|
|
|
*/
|
|
|
empty () {
|
|
|
this.$confirm('确定清空页面吗?', '提示', {
|
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning',
|
|
|
customClass: 'bs-el-message-box'
|
|
|
})
|
|
|
.then(() => {
|
|
|
this.changeLayout([])
|
|
|
this.resetPresetLine()
|
|
|
this.saveTimeLine('清空画布')
|
|
|
})
|
|
|
.catch(() => {})
|
|
|
},
|
|
|
// 自定义属性更新
|
|
|
updateSetting (config) {
|
|
|
if (config.type === 'map' || config.type === 'video') {
|
|
|
config.key = new Date().getTime()
|
|
|
}
|
|
|
this.changeChartConfig(_.cloneDeep(config))
|
|
|
this.$refs.Render?.$refs['RenderCard' + config.code][0]?.$refs[
|
|
|
config.code
|
|
|
]?.changeStyle(_.cloneDeep(config))
|
|
|
},
|
|
|
// 动态属性更新
|
|
|
updateDataSetting (config) {
|
|
|
config.key = new Date().getTime()
|
|
|
this.changeChartConfig(config)
|
|
|
},
|
|
|
onSelectArea (area) {
|
|
|
const { startX, startY, endX, endY } = area
|
|
|
// 计算所有在此区域中的组件,如果在此区域中,将其code添加到activeCodes数组中
|
|
|
const activeCodes = this.chartList
|
|
|
?.filter((chart) => {
|
|
|
const { x, y, w, h } = chart
|
|
|
return startX <= x && x + w <= endX && startY <= y && y + h <= endY
|
|
|
})
|
|
|
?.map((chart) => chart.code)
|
|
|
this.changeActiveCodes(activeCodes)
|
|
|
},
|
|
|
changeStart ({ x, y }) {
|
|
|
this.ruleStartX = x
|
|
|
this.ruleStartY = y
|
|
|
},
|
|
|
// 保存并预览
|
|
|
saveAndPreview () {
|
|
|
this.$refs.PageTopSetting.execRun()
|
|
|
},
|
|
|
// 保存
|
|
|
save () {
|
|
|
this.$refs.PageTopSetting.save('saveLoading')
|
|
|
},
|
|
|
changeScreenZoom (zoom) {
|
|
|
// 自适应
|
|
|
if (zoom === 'auto') {
|
|
|
this.$refs.Rules.initZoom()
|
|
|
} else {
|
|
|
this.changeZoom(zoom)
|
|
|
}
|
|
|
},
|
|
|
updateRightVisiable (visiable) {
|
|
|
this.rightVisiable = visiable
|
|
|
this.$refs.Rules.initRuleHeight()
|
|
|
},
|
|
|
toggleLeftSidebar () {
|
|
|
this.$refs.Rules.initRuleHeight()
|
|
|
},
|
|
|
showPageInfo () {
|
|
|
this.pageInfoVisiable = true
|
|
|
this.rightVisiable = true
|
|
|
this.changeActiveCode('')
|
|
|
},
|
|
|
// 页面信息更改
|
|
|
updatePage () {
|
|
|
this.$refs.Rules.initZoom()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
.bs-page-design-wrap {
|
|
|
overflow: hidden;
|
|
|
|
|
|
.drag-wrap {
|
|
|
display: flex;
|
|
|
background-color: #1d1e20;
|
|
|
height: calc(100vh - 40px);
|
|
|
overflow: hidden;
|
|
|
|
|
|
.grid-wrap-box {
|
|
|
flex: 1;
|
|
|
overflow: hidden;
|
|
|
position: relative;
|
|
|
margin: 8px 0 0 8px;
|
|
|
|
|
|
.footer-tools-bar {
|
|
|
position: absolute;
|
|
|
bottom: 0;
|
|
|
width: 100%;
|
|
|
height: 30px;
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
align-items: center;
|
|
|
z-index: 1000;
|
|
|
background-color: var(--bs-background-2);
|
|
|
|
|
|
.bs-select-wrap {
|
|
|
margin-right: 16px;
|
|
|
}
|
|
|
|
|
|
.select-zoom-text {
|
|
|
color: var(--bs-el-title);
|
|
|
margin-right: 16px;
|
|
|
}
|
|
|
|
|
|
::v-deep .el-select {
|
|
|
width: 150px !important;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
::v-deep .el-loading-mask {
|
|
|
background-color: transparent !important;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</style>
|