forked from github/dataease
feat: 仪表板支持移动端布局展示
This commit is contained in:
parent
d0f24db4b9
commit
5998a6c286
@ -9,7 +9,7 @@
|
||||
@mouseup="deselectCurComponent"
|
||||
@mousedown="handleMouseDown"
|
||||
>
|
||||
<el-row v-if="componentDataShow.length===0" style="height: 100%;" class="custom-position">
|
||||
<el-row v-if="componentDataShow.length===0" class="custom-position">
|
||||
{{ $t('panel.panelNull') }}
|
||||
</el-row>
|
||||
<canvas-opt-bar />
|
||||
@ -103,7 +103,15 @@ export default {
|
||||
searchCount: 0,
|
||||
chartDetailsVisible: false,
|
||||
showChartInfo: {},
|
||||
showChartTableInfo: {}
|
||||
showChartTableInfo: {},
|
||||
// 布局展示 1.pc pc端布局 2.mobile 移动端布局
|
||||
terminal: 'pc'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const terminalInfo = this.$route.query.terminal
|
||||
if (terminalInfo) {
|
||||
this.terminal = terminalInfo
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -158,16 +166,15 @@ export default {
|
||||
mounted() {
|
||||
const _this = this
|
||||
const erd = elementResizeDetectorMaker()
|
||||
// 监听div变动事件
|
||||
const mainDom = document.getElementById('canvasInfoMain')
|
||||
erd.listenTo(mainDom, element => {
|
||||
// 监听主div变动事件
|
||||
erd.listenTo(document.getElementById('canvasInfoMain'), element => {
|
||||
_this.$nextTick(() => {
|
||||
_this.restore()
|
||||
})
|
||||
})
|
||||
// 监听div变动事件
|
||||
// 监听画布div变动事件
|
||||
const tempCanvas = document.getElementById('canvasInfoTemp')
|
||||
erd.listenTo(tempCanvas, element => {
|
||||
erd.listenTo(document.getElementById('canvasInfoTemp'), element => {
|
||||
_this.$nextTick(() => {
|
||||
// 将mainHeight 修改为px 临时解决html2canvas 截图不全的问题
|
||||
_this.mainHeight = tempCanvas.scrollHeight + 'px!important'
|
||||
@ -176,6 +183,10 @@ export default {
|
||||
eventBus.$on('openChartDetailsDialog', this.openChartDetailsDialog)
|
||||
_this.$store.commit('clearLinkageSettingInfo', false)
|
||||
_this.canvasStyleDataInit()
|
||||
// 如果当前终端设备是移动端,则进行移动端的布局设计
|
||||
if (_this.terminal === 'mobile') {
|
||||
_this.initMobileCanvas()
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer)
|
||||
@ -249,6 +260,9 @@ export default {
|
||||
},
|
||||
handleMouseDown() {
|
||||
this.$store.commit('setClickComponentStatus', false)
|
||||
},
|
||||
initMobileCanvas() {
|
||||
this.$store.commit('openMobileLayout')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,7 +271,7 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.bg {
|
||||
padding: 5px;
|
||||
min-width: 600px;
|
||||
min-width: 200px;
|
||||
min-height: 300px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@ -272,6 +286,7 @@ export default {
|
||||
}
|
||||
|
||||
.custom-position {
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<div class="bg" :style="customStyle">
|
||||
<div id="canvasInfoMain" ref="canvasInfoMain" style="width: 100%;height: 100%">
|
||||
<div
|
||||
id="canvasInfoTemp"
|
||||
ref="canvasInfoTemp"
|
||||
:style="[{height:mainHeight},screenShotStyle]"
|
||||
class="main-class"
|
||||
@mouseup="deselectCurComponent"
|
||||
@mousedown="handleMouseDown"
|
||||
>
|
||||
<el-row v-if="componentDataShow.length===0" style="height: 100%;" class="custom-position">
|
||||
{{ $t('panel.panelNull') }}
|
||||
</el-row>
|
||||
<canvas-opt-bar />
|
||||
<ComponentWrapper
|
||||
v-for="(item, index) in componentDataInfo"
|
||||
:key="index"
|
||||
:config="item"
|
||||
:search-count="searchCount"
|
||||
:in-screen="inScreen"
|
||||
/>
|
||||
<!--视图详情-->
|
||||
<el-dialog
|
||||
:title="'['+showChartInfo.name+']'+$t('chart.chart_details')"
|
||||
:visible.sync="chartDetailsVisible"
|
||||
width="70%"
|
||||
class="dialog-css"
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<span style="position: absolute;right: 70px;top:15px">
|
||||
<el-button size="mini" @click="exportExcel">
|
||||
<svg-icon icon-class="ds-excel" class="ds-icon-excel" />
|
||||
{{ $t('chart.export_details') }}
|
||||
</el-button>
|
||||
</span>
|
||||
<UserViewDialog ref="userViewDialog" :chart="showChartInfo" :chart-table="showChartTableInfo" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getStyle } from '@/components/canvas/utils/style'
|
||||
import { mapState } from 'vuex'
|
||||
import ComponentWrapper from './ComponentWrapper'
|
||||
import { changeStyleWithScale } from '@/components/canvas/utils/translate'
|
||||
import { uuid } from 'vue-uuid'
|
||||
import { deepCopy } from '@/components/canvas/utils/utils'
|
||||
import eventBus from '@/components/canvas/utils/eventBus'
|
||||
import elementResizeDetectorMaker from 'element-resize-detector'
|
||||
import UserViewDialog from '@/components/canvas/custom-component/UserViewDialog'
|
||||
import CanvasOptBar from '@/components/canvas/components/Editor/CanvasOptBar'
|
||||
|
||||
export default {
|
||||
components: { ComponentWrapper, UserViewDialog, CanvasOptBar },
|
||||
model: {
|
||||
prop: 'show',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
screenShot: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showType: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'full'
|
||||
},
|
||||
inScreen: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowPreview: false,
|
||||
panelId: '',
|
||||
needToChangeHeight: [
|
||||
'top',
|
||||
'height'
|
||||
],
|
||||
needToChangeWidth: [
|
||||
'left',
|
||||
'width',
|
||||
'fontSize',
|
||||
'borderWidth',
|
||||
'letterSpacing'
|
||||
],
|
||||
scaleWidth: '100',
|
||||
scaleHeight: '100',
|
||||
timer: null,
|
||||
componentDataShow: [],
|
||||
mainWidth: '100%',
|
||||
mainHeight: '100%',
|
||||
searchCount: 0,
|
||||
chartDetailsVisible: false,
|
||||
showChartInfo: {},
|
||||
showChartTableInfo: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
customStyle() {
|
||||
let style = {
|
||||
width: '100%'
|
||||
}
|
||||
if (this.canvasStyleData.openCommonStyle) {
|
||||
if (this.canvasStyleData.panel.backgroundType === 'image' && this.canvasStyleData.panel.imageUrl) {
|
||||
style = {
|
||||
background: `url(${this.canvasStyleData.panel.imageUrl}) no-repeat`,
|
||||
...style
|
||||
}
|
||||
} else if (this.canvasStyleData.panel.backgroundType === 'color') {
|
||||
style = {
|
||||
background: this.canvasStyleData.panel.color,
|
||||
...style
|
||||
}
|
||||
}
|
||||
}
|
||||
return style
|
||||
},
|
||||
screenShotStyle() {
|
||||
return this.screenShot ? this.customStyle : {}
|
||||
},
|
||||
// 此处单独计算componentData的值 不放入全局mapState中
|
||||
componentDataInfo() {
|
||||
return this.componentDataShow
|
||||
},
|
||||
...mapState([
|
||||
'isClickComponent',
|
||||
'curComponent',
|
||||
'componentData',
|
||||
'canvasStyleData',
|
||||
'componentGap'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
componentData: {
|
||||
handler(newVal, oldVla) {
|
||||
this.restore()
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
canvasStyleData: {
|
||||
handler(newVal, oldVla) {
|
||||
this.canvasStyleDataInit()
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const _this = this
|
||||
const erd = elementResizeDetectorMaker()
|
||||
// 监听div变动事件
|
||||
const mainDom = document.getElementById('canvasInfoMain')
|
||||
erd.listenTo(mainDom, element => {
|
||||
_this.$nextTick(() => {
|
||||
_this.restore()
|
||||
})
|
||||
})
|
||||
// 监听div变动事件
|
||||
const tempCanvas = document.getElementById('canvasInfoTemp')
|
||||
erd.listenTo(tempCanvas, element => {
|
||||
_this.$nextTick(() => {
|
||||
// 将mainHeight 修改为px 临时解决html2canvas 截图不全的问题
|
||||
_this.mainHeight = tempCanvas.scrollHeight + 'px!important'
|
||||
})
|
||||
})
|
||||
eventBus.$on('openChartDetailsDialog', this.openChartDetailsDialog)
|
||||
_this.$store.commit('clearLinkageSettingInfo', false)
|
||||
_this.canvasStyleDataInit()
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
methods: {
|
||||
canvasStyleDataInit() {
|
||||
// 数据刷新计时器
|
||||
this.searchCount = 0
|
||||
this.timer && clearInterval(this.timer)
|
||||
let refreshTime = 300000
|
||||
if (this.canvasStyleData.refreshTime && this.canvasStyleData.refreshTime > 0) {
|
||||
if (this.canvasStyleData.refreshUnit === 'second') {
|
||||
refreshTime = this.canvasStyleData.refreshTime * 1000
|
||||
} else {
|
||||
refreshTime = this.canvasStyleData.refreshTime * 60000
|
||||
}
|
||||
}
|
||||
this.timer = setInterval(() => {
|
||||
this.searchCount++
|
||||
}, refreshTime)
|
||||
},
|
||||
changeStyleWithScale,
|
||||
getStyle,
|
||||
restore() {
|
||||
const canvasHeight = document.getElementById('canvasInfoMain').offsetHeight
|
||||
const canvasWidth = document.getElementById('canvasInfoMain').offsetWidth
|
||||
this.scaleWidth = canvasWidth * 100 / parseInt(this.canvasStyleData.width)// 获取宽度比
|
||||
this.scaleHeight = canvasHeight * 100 / parseInt(this.canvasStyleData.height)// 获取高度比
|
||||
this.handleScaleChange()
|
||||
},
|
||||
resetID(data) {
|
||||
if (data) {
|
||||
data.forEach(item => {
|
||||
item.type !== 'custom' && (item.id = uuid.v1())
|
||||
})
|
||||
}
|
||||
return data
|
||||
},
|
||||
format(value, scale) {
|
||||
return value * parseInt(scale) / 100
|
||||
},
|
||||
handleScaleChange() {
|
||||
if (this.componentData) {
|
||||
const componentData = deepCopy(this.componentData)
|
||||
componentData.forEach(component => {
|
||||
Object.keys(component.style).forEach(key => {
|
||||
if (this.needToChangeHeight.includes(key)) {
|
||||
component.style[key] = this.format(component.style[key], this.scaleHeight)
|
||||
}
|
||||
if (this.needToChangeWidth.includes(key)) {
|
||||
component.style[key] = this.format(component.style[key], this.scaleWidth)
|
||||
}
|
||||
})
|
||||
})
|
||||
this.componentDataShow = componentData
|
||||
this.$nextTick(() => (eventBus.$emit('resizing', '')))
|
||||
}
|
||||
},
|
||||
openChartDetailsDialog(chartInfo) {
|
||||
this.showChartInfo = chartInfo.chart
|
||||
this.showChartTableInfo = chartInfo.tableChart
|
||||
this.chartDetailsVisible = true
|
||||
},
|
||||
exportExcel() {
|
||||
this.$refs['userViewDialog'].exportExcel()
|
||||
},
|
||||
deselectCurComponent(e) {
|
||||
if (!this.isClickComponent) {
|
||||
this.$store.commit('setCurComponent', { component: null, index: null })
|
||||
}
|
||||
},
|
||||
handleMouseDown() {
|
||||
this.$store.commit('setClickComponentStatus', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bg {
|
||||
padding: 5px;
|
||||
min-width: 600px;
|
||||
min-height: 300px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
background-size: 100% 100% !important;
|
||||
}
|
||||
|
||||
.main-class {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: 100% 100% !important;
|
||||
}
|
||||
|
||||
.custom-position {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
flex-flow: row nowrap;
|
||||
color: #9ea6b2;
|
||||
}
|
||||
|
||||
.gap_class {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.dialog-css > > > .el-dialog__title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.dialog-css > > > .el-dialog__header {
|
||||
padding: 20px 20px 0;
|
||||
}
|
||||
|
||||
.dialog-css > > > .el-dialog__body {
|
||||
padding: 10px 20px 20px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0px!important;
|
||||
height: 0px!important;
|
||||
}
|
||||
|
||||
</style>
|
@ -347,25 +347,9 @@ export default {
|
||||
auxiliaryMatrixChange() {
|
||||
this.canvasStyleData.auxiliaryMatrix = !this.canvasStyleData.auxiliaryMatrix
|
||||
},
|
||||
// 启用移动端布局
|
||||
openMobileLayout() {
|
||||
this.$store.commit('setComponentDataCache', JSON.stringify(this.componentData))
|
||||
this.$store.commit('setPcComponentData', this.componentData)
|
||||
const mainComponentData = []
|
||||
// 移动端布局转换
|
||||
this.componentData.forEach(item => {
|
||||
if (item.mobileSelected) {
|
||||
item.style = item.mobileStyle.style
|
||||
item.x = item.mobileStyle.x
|
||||
item.y = item.mobileStyle.y
|
||||
item.sizex = item.mobileStyle.sizex
|
||||
item.sizey = item.mobileStyle.sizey
|
||||
item.auxiliaryMatrix = item.mobileStyle.auxiliaryMatrix
|
||||
mainComponentData.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
this.$store.commit('setComponentData', mainComponentData)
|
||||
this.$store.commit('setMobileLayoutStatus', !this.mobileLayoutStatus)
|
||||
this.$store.commit('openMobileLayout')
|
||||
},
|
||||
editSave() {
|
||||
if (this.mobileLayoutStatus) {
|
||||
|
@ -325,6 +325,26 @@ const data = {
|
||||
},
|
||||
setMobileLayoutStatus(state, status) {
|
||||
state.mobileLayoutStatus = status
|
||||
},
|
||||
// 启用移动端布局
|
||||
openMobileLayout(state) {
|
||||
state.componentDataCache = JSON.stringify(state.componentData)
|
||||
state.pcComponentData = state.componentData
|
||||
const mainComponentData = []
|
||||
// 移动端布局转换
|
||||
state.componentData.forEach(item => {
|
||||
if (item.mobileSelected) {
|
||||
item.style = item.mobileStyle.style
|
||||
item.x = item.mobileStyle.x
|
||||
item.y = item.mobileStyle.y
|
||||
item.sizex = item.mobileStyle.sizex
|
||||
item.sizey = item.mobileStyle.sizey
|
||||
item.auxiliaryMatrix = item.mobileStyle.auxiliaryMatrix
|
||||
mainComponentData.push(item)
|
||||
}
|
||||
})
|
||||
state.componentData = mainComponentData
|
||||
state.mobileLayoutStatus = !state.mobileLayoutStatus
|
||||
}
|
||||
},
|
||||
modules: {
|
||||
|
@ -82,7 +82,6 @@ export default {
|
||||
width: 100%;
|
||||
height: calc(100% - 30px);
|
||||
overflow-y: auto;
|
||||
background-color: lightgray;
|
||||
}
|
||||
.component-custom {
|
||||
outline: none;
|
||||
|
@ -8,6 +8,7 @@
|
||||
v-if="config.type==='custom'"
|
||||
:id="'component' + config.id"
|
||||
class="component-custom"
|
||||
:style="getComponentStyleDefault(config.style)"
|
||||
:out-style="outStyle"
|
||||
:element="config"
|
||||
/>
|
||||
@ -17,6 +18,7 @@
|
||||
ref="wrapperChild"
|
||||
:out-style="outStyle"
|
||||
:prop-value="config.propValue"
|
||||
:style="getComponentStyleDefault(config.style)"
|
||||
:is-edit="false"
|
||||
:element="config"
|
||||
:h="itemHeight"
|
||||
@ -27,6 +29,7 @@
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import MobileCheckBar from '@/components/canvas/components/Editor/MobileCheckBar'
|
||||
import { getStyle } from '@/components/canvas/utils/style'
|
||||
|
||||
export default {
|
||||
name: 'ComponentWaitItem',
|
||||
@ -75,6 +78,9 @@ export default {
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
getComponentStyleDefault(style) {
|
||||
return getStyle(style, ['top', 'left', 'width', 'height', 'rotate'])
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -125,13 +125,14 @@
|
||||
<el-row
|
||||
id="canvasInfoMobile"
|
||||
class="this_mobile_canvas_main"
|
||||
:style="mobileCanvasStyle"
|
||||
>
|
||||
<Editor ref="editorMobile" :matrix-count="mobileMatrixCount" :out-style="outStyle" :scroll-top="scrollTop" />
|
||||
</el-row>
|
||||
<el-row class="this_mobile_canvas_bottom" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="16" class="this_mobile_canvas_cell">
|
||||
<el-col :span="16" class="this_mobile_canvas_cell this_mobile_canvas_wait_cell" :style="mobileCanvasStyle">
|
||||
<component-wait />
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -336,6 +337,25 @@ export default {
|
||||
padding: this.componentGap + 'px'
|
||||
}
|
||||
},
|
||||
mobileCanvasStyle() {
|
||||
let style
|
||||
if (this.canvasStyleData.openCommonStyle) {
|
||||
if (this.canvasStyleData.panel.backgroundType === 'image' && this.canvasStyleData.panel.imageUrl) {
|
||||
style = {
|
||||
background: `url(${this.canvasStyleData.panel.imageUrl}) no-repeat`
|
||||
}
|
||||
} else if (this.canvasStyleData.panel.backgroundType === 'color') {
|
||||
style = {
|
||||
background: this.canvasStyleData.panel.color
|
||||
}
|
||||
} else {
|
||||
style = {
|
||||
background: '#f7f8fa'
|
||||
}
|
||||
}
|
||||
}
|
||||
return style
|
||||
},
|
||||
customCanvasStyle() {
|
||||
let style = {
|
||||
padding: this.componentGap + 'px'
|
||||
@ -684,7 +704,6 @@ export default {
|
||||
},
|
||||
closeLeftPanel() {
|
||||
this.show = false
|
||||
// this.beforeDestroy()
|
||||
},
|
||||
previewFullScreen() {
|
||||
this.previewVisible = true
|
||||
@ -975,6 +994,10 @@ export default {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.this_mobile_canvas_wait_cell{
|
||||
background-size:100% 100% !important;
|
||||
border: 2px solid #9ea6b2
|
||||
}
|
||||
|
||||
.this_canvas{
|
||||
width: 100%;
|
||||
|
Loading…
Reference in New Issue
Block a user