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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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