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" @mouseup="deselectCurComponent"
@mousedown="handleMouseDown" @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') }} {{ $t('panel.panelNull') }}
</el-row> </el-row>
<canvas-opt-bar /> <canvas-opt-bar />
@ -103,7 +103,15 @@ export default {
searchCount: 0, searchCount: 0,
chartDetailsVisible: false, chartDetailsVisible: false,
showChartInfo: {}, showChartInfo: {},
showChartTableInfo: {} showChartTableInfo: {},
// 1.pc pc 2.mobile
terminal: 'pc'
}
},
created() {
const terminalInfo = this.$route.query.terminal
if (terminalInfo) {
this.terminal = terminalInfo
} }
}, },
computed: { computed: {
@ -158,16 +166,15 @@ export default {
mounted() { mounted() {
const _this = this const _this = this
const erd = elementResizeDetectorMaker() const erd = elementResizeDetectorMaker()
// div // div
const mainDom = document.getElementById('canvasInfoMain') erd.listenTo(document.getElementById('canvasInfoMain'), element => {
erd.listenTo(mainDom, element => {
_this.$nextTick(() => { _this.$nextTick(() => {
_this.restore() _this.restore()
}) })
}) })
// div // div
const tempCanvas = document.getElementById('canvasInfoTemp') const tempCanvas = document.getElementById('canvasInfoTemp')
erd.listenTo(tempCanvas, element => { erd.listenTo(document.getElementById('canvasInfoTemp'), element => {
_this.$nextTick(() => { _this.$nextTick(() => {
// mainHeight px html2canvas // mainHeight px html2canvas
_this.mainHeight = tempCanvas.scrollHeight + 'px!important' _this.mainHeight = tempCanvas.scrollHeight + 'px!important'
@ -176,6 +183,10 @@ export default {
eventBus.$on('openChartDetailsDialog', this.openChartDetailsDialog) eventBus.$on('openChartDetailsDialog', this.openChartDetailsDialog)
_this.$store.commit('clearLinkageSettingInfo', false) _this.$store.commit('clearLinkageSettingInfo', false)
_this.canvasStyleDataInit() _this.canvasStyleDataInit()
//
if (_this.terminal === 'mobile') {
_this.initMobileCanvas()
}
}, },
beforeDestroy() { beforeDestroy() {
clearInterval(this.timer) clearInterval(this.timer)
@ -249,6 +260,9 @@ export default {
}, },
handleMouseDown() { handleMouseDown() {
this.$store.commit('setClickComponentStatus', false) this.$store.commit('setClickComponentStatus', false)
},
initMobileCanvas() {
this.$store.commit('openMobileLayout')
} }
} }
} }
@ -257,7 +271,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.bg { .bg {
padding: 5px; padding: 5px;
min-width: 600px; min-width: 200px;
min-height: 300px; min-height: 300px;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -272,6 +286,7 @@ export default {
} }
.custom-position { .custom-position {
height: 100%;
flex: 1; flex: 1;
display: flex; display: flex;
align-items: center; 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() { auxiliaryMatrixChange() {
this.canvasStyleData.auxiliaryMatrix = !this.canvasStyleData.auxiliaryMatrix this.canvasStyleData.auxiliaryMatrix = !this.canvasStyleData.auxiliaryMatrix
}, },
//
openMobileLayout() { openMobileLayout() {
this.$store.commit('setComponentDataCache', JSON.stringify(this.componentData)) this.$store.commit('openMobileLayout')
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)
}, },
editSave() { editSave() {
if (this.mobileLayoutStatus) { if (this.mobileLayoutStatus) {

View File

@ -325,6 +325,26 @@ const data = {
}, },
setMobileLayoutStatus(state, status) { setMobileLayoutStatus(state, status) {
state.mobileLayoutStatus = 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: { modules: {

View File

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

View File

@ -8,6 +8,7 @@
v-if="config.type==='custom'" v-if="config.type==='custom'"
:id="'component' + config.id" :id="'component' + config.id"
class="component-custom" class="component-custom"
:style="getComponentStyleDefault(config.style)"
:out-style="outStyle" :out-style="outStyle"
:element="config" :element="config"
/> />
@ -17,6 +18,7 @@
ref="wrapperChild" ref="wrapperChild"
:out-style="outStyle" :out-style="outStyle"
:prop-value="config.propValue" :prop-value="config.propValue"
:style="getComponentStyleDefault(config.style)"
:is-edit="false" :is-edit="false"
:element="config" :element="config"
:h="itemHeight" :h="itemHeight"
@ -27,6 +29,7 @@
<script> <script>
import { mapState } from 'vuex' import { mapState } from 'vuex'
import MobileCheckBar from '@/components/canvas/components/Editor/MobileCheckBar' import MobileCheckBar from '@/components/canvas/components/Editor/MobileCheckBar'
import { getStyle } from '@/components/canvas/utils/style'
export default { export default {
name: 'ComponentWaitItem', name: 'ComponentWaitItem',
@ -75,6 +78,9 @@ export default {
]) ])
}, },
methods: { methods: {
getComponentStyleDefault(style) {
return getStyle(style, ['top', 'left', 'width', 'height', 'rotate'])
}
} }
} }
</script> </script>

View File

@ -125,13 +125,14 @@
<el-row <el-row
id="canvasInfoMobile" id="canvasInfoMobile"
class="this_mobile_canvas_main" class="this_mobile_canvas_main"
:style="mobileCanvasStyle"
> >
<Editor ref="editorMobile" :matrix-count="mobileMatrixCount" :out-style="outStyle" :scroll-top="scrollTop" /> <Editor ref="editorMobile" :matrix-count="mobileMatrixCount" :out-style="outStyle" :scroll-top="scrollTop" />
</el-row> </el-row>
<el-row class="this_mobile_canvas_bottom" /> <el-row class="this_mobile_canvas_bottom" />
</div> </div>
</el-col> </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 /> <component-wait />
</el-col> </el-col>
</el-row> </el-row>
@ -336,6 +337,25 @@ export default {
padding: this.componentGap + 'px' 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() { customCanvasStyle() {
let style = { let style = {
padding: this.componentGap + 'px' padding: this.componentGap + 'px'
@ -684,7 +704,6 @@ export default {
}, },
closeLeftPanel() { closeLeftPanel() {
this.show = false this.show = false
// this.beforeDestroy()
}, },
previewFullScreen() { previewFullScreen() {
this.previewVisible = true this.previewVisible = true
@ -975,6 +994,10 @@ export default {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.this_mobile_canvas_wait_cell{
background-size:100% 100% !important;
border: 2px solid #9ea6b2
}
.this_canvas{ .this_canvas{
width: 100%; width: 100%;