feat: 仪表板支持移动端布局展示

This commit is contained in:
wangjiahao 2021-12-07 17:32:02 +08:00
parent d0f24db4b9
commit 5998a6c286
7 changed files with 381 additions and 29 deletions

View File

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

View File

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

View File

@ -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) {

View File

@ -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: {

View File

@ -82,7 +82,6 @@ export default {
width: 100%;
height: calc(100% - 30px);
overflow-y: auto;
background-color: lightgray;
}
.component-custom {
outline: none;

View File

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

View File

@ -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%;