You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
14 KiB
Vue

<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>