<template>
|
<div class="bs-page-design-wrap">
|
<PageTopSetting v-show="headerShow" ref="PageTopSetting" :right-fold="rightVisiable"
|
@updateRightVisiable="updateRightVisiable" @showPageInfo="showPageInfo" @changeZoom="changeScreenZoom"
|
@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">
|
<div id="minimap" class="minimap">
|
<div class="mapHeader" id="mapHeader">
|
<div>
|
<span>小地图</span>
|
</div>
|
<div class="showMap" @click="showMinimap">
|
<i class="el-icon-arrow-down" style="width:20px;height:20px;color:#fff;" v-if="!mapShow" />
|
<i class="el-icon-arrow-up" style="width:20px;height:20px;color:#fff;" v-if="mapShow" />
|
</div>
|
</div>
|
<div id="selectWin" class="selectWin" v-show="mapShow">
|
<div id="selectionWin" class="selectionWin" />
|
</div>
|
</div>
|
<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" @openDataViewDialog="openDataViewDialog" />
|
</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" @styleHandler="styleHandler">
|
<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>
|
<data-view-dialog ref="dataViewDialog" />
|
</div>
|
|
</template>
|
<script>
|
import {
|
getToken,
|
setToken,
|
removeToken
|
} from '@/utils/auth'
|
|
|
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 multipleSelectMixin from 'data-room-ui/js/mixins/multipleSelectMixin'
|
import {
|
getScreenInfo
|
} from 'data-room-ui/js/api/bigScreenApi'
|
import plotSettings from 'data-room-ui/G2Plots/settings'
|
import MouseSelect from './MouseSelect/index.vue'
|
import cloneDeep from 'lodash/cloneDeep'
|
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'
|
import DataViewDialog from 'data-room-ui/BigScreenDesign/DataViewDialog'
|
|
|
export default {
|
name: 'BigScreenDesign',
|
components: {
|
|
|
PageTopSetting,
|
LeftPanel,
|
Render,
|
SketchDesignRuler,
|
MouseSelect,
|
SettingPanel,
|
SourceDialog,
|
ComponentDialog,
|
iframeDialog,
|
NotPermission,
|
DataViewDialog
|
},
|
mixins: [multipleSelectMixin],
|
props: {
|
code: {
|
type: String,
|
default: ''
|
},
|
headerShow: {
|
type: Boolean,
|
default: true
|
},
|
height: {
|
type: String,
|
default: 'calc(100vh - 40px)'
|
}
|
},
|
data() {
|
return {
|
mapShow: true, // 小地图显示与否
|
hasPermission: false,
|
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: {
|
chartList(val) {
|
// if(val.findIndex(item=>item.code==this.activeCode)==-1){
|
// this.updateRightVisiable(false)
|
// }
|
// if(val.length==0){
|
// this.updateRightVisiable(false)
|
// }
|
},
|
mapShow(value) {
|
const mapElement = document.getElementById('minimap')
|
// const selectElement = document.getElementById('selectWin')
|
if (!value) {
|
mapElement.style.bottom = parseFloat(window.getComputedStyle(mapElement).bottom) + 150 + 'px'
|
} else {
|
this.$refs.Rules.handleScroll()
|
mapElement.style.bottom = parseFloat(window.getComputedStyle(mapElement).bottom) - 150 + 'px'
|
}
|
},
|
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,
|
activeCode: state => state.bigScreen.activeCode
|
}),
|
pageCode() {
|
return this.code || this.$route.query.code
|
},
|
|
offset() {
|
return {
|
x: 220 + 50 - this.ruleStartX,
|
y: 55 + 50 - this.ruleStartY
|
}
|
}
|
},
|
created() {
|
// console.log("href",window.location.href);
|
if (this.$route.query.token != null) { //从传参写入token
|
setToken(this.$route.query.token)
|
this.$store.commit('SET_TOKEN', this.$route.query.token)
|
//console.log("token传参置入成功!");
|
|
}
|
|
this.init(); //手动初始化
|
this.changePageLoading(true)
|
/**
|
* 以下是为了解决在火狐浏览器上推拽时弹出tab页到搜索问题
|
* @param event
|
*/
|
if (isFirefox()) {
|
document.body.ondrop = function(event) {
|
event.preventDefault()
|
event.stopPropagation()
|
}
|
}
|
},
|
mounted() {
|
EventBus.$on('closeRightPanel', () => {
|
this.updateRightVisiable(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',
|
'changePageInfo',
|
'changeActiveItemConfig',
|
'emptyDataset',
|
'emptyComputedDatas'
|
]),
|
token() {
|
return this.$route.query.token
|
},
|
// 控制小地图显示与隐藏
|
showMinimap() {
|
this.mapShow = !this.mapShow
|
},
|
// 判断页面权限
|
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 => {
|
res.chartList.forEach((item) => {
|
if (!item.border) {
|
item.border = {
|
type: '',
|
titleHeight: 60,
|
fontSize: 16,
|
isTitle: true,
|
padding: [0, 0, 0, 0]
|
}
|
}
|
if (!item.border.padding) {
|
item.border.padding = [0, 0, 0, 0]
|
}
|
if (item.type == 'customComponent') {
|
plotSettings[Symbol.iterator] = function*() {
|
const keys = Object.keys(plotSettings)
|
for (const k of keys) {
|
yield [k, plotSettings[k]]
|
}
|
}
|
for (const [key, value] of plotSettings) {
|
if (item.name == value.name) {
|
const settings = JSON.parse(JSON.stringify(value.setting))
|
item.setting = settings.map((x) => {
|
const index = item.setting.findIndex(y => y.field == x
|
.field)
|
x.field = item.setting[index].field
|
x.value = item.setting[index].value
|
return x
|
})
|
}
|
}
|
}
|
})
|
// 给组件库导入的组件加入统一的前缀
|
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
|
}
|
// 如果是从组件库中添加的自定义组件,则不需要初始化theme
|
const isComponent = true
|
this.$refs.Render.addChart(newChart, {
|
x: chart.x,
|
y: chart.y
|
}, isComponent)
|
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.sxlinks.modules.system.components.visual.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(() => {
|
this.changePageLoading(false)
|
})
|
.finally(() => {
|
setTimeout(() => {
|
this.resetPresetLine()
|
}, 500)
|
})
|
},
|
// 点击当前组件时打开右侧面板
|
openRightPanel(card) {
|
this.rightVisiable = true
|
this.pageInfoVisiable = false
|
this.$refs.Rules.initRuleHeight()
|
},
|
openDataViewDialog(config) {
|
this.$refs.dataViewDialog.init(config)
|
},
|
/**
|
* @description: 清空页面
|
*/
|
empty() {
|
this.$confirm('确定清空页面吗?', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning',
|
customClass: 'bs-el-message-box'
|
})
|
.then(() => {
|
this.changeLayout([])
|
// 清空缓存的数据库的内容
|
this.emptyDataset()
|
this.emptyComputedDatas()
|
this.resetPresetLine()
|
this.saveTimeLine('清空画布')
|
})
|
.catch(() => {})
|
},
|
// 切换主题时针对远程组件触发样式修改的方法
|
styleHandler(config) {
|
this.$nextTick(() => {
|
this.$refs.Render?.$refs['RenderCard' + config.code][0]?.$refs[
|
config.code
|
]?.changeStyle(cloneDeep(config), true)
|
})
|
},
|
// 自定义属性更新
|
updateSetting(config) {
|
if (config.type === 'map' || config.type === 'screenScrollBoard' || config.type === 'remoteComponent' ||
|
config.type === 'video' || config.type === 'flyMap') {
|
config.key = new Date().getTime()
|
}
|
this.changeChartConfig(cloneDeep(config))
|
// 如果是tab内的组件
|
if (config.parentCode) {
|
const dom = this.$refs.Render?.$refs['RenderCard' + config.parentCode][0]?.$refs[config.parentCode]
|
?.$refs['RenderCard' + config.code]?.$refs[config.code]
|
if (dom) {
|
dom?.changeStyle(cloneDeep(config))
|
}
|
} else {
|
if (this.$refs.Render?.$refs['RenderCard' + config.code]) {
|
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 - 50 <= x && x + w <= endX && startY - 50 <= 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;
|
}
|
}
|
}
|
|
.minimap {
|
position: absolute;
|
bottom: 20px;
|
right: 20px;
|
z-index: 1000;
|
}
|
|
.minimap .mapHeader {
|
background-color: #303640;
|
box-sizing: border-box;
|
padding: 0 10px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
height: 30px;
|
width: 150px;
|
font-size: 12px;
|
color: var(--bs-el-title);
|
cursor: pointer;
|
|
span {
|
user-select: none;
|
}
|
}
|
|
.minimap .selectWin {
|
background-color: #232832;
|
height: 150px;
|
width: 150px;
|
position: relative;
|
}
|
|
.minimap .selectionWin {
|
position: absolute;
|
left: 0px;
|
top: 0px;
|
width: 30px;
|
height: 30px;
|
background-color: white;
|
opacity: 0.5;
|
cursor: move;
|
}
|
</style>
|