Merge pull request #6536 from dataease/pr@dev_mobile_time
feat: 移动端时间组件
This commit is contained in:
commit
9c56c67063
@ -72,6 +72,7 @@
|
||||
"svgo": "1.2.2",
|
||||
"tinymce": "^5.8.2",
|
||||
"umy-ui": "^1.1.6",
|
||||
"vant": "^2.13.2",
|
||||
"vue": "2.6.10",
|
||||
"vue-clipboard2": "0.3.1",
|
||||
"vue-codemirror": "^4.0.6",
|
||||
|
||||
16
core/frontend/public/mobile.html
Normal file
16
core/frontend/public/mobile.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
|
||||
/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-mobile"></div>
|
||||
</body>
|
||||
</html>
|
||||
@ -342,6 +342,7 @@ export default {
|
||||
eventBus.$on('checkAndSave', this.checkAndSave)
|
||||
eventBus.$on('clearCanvas', this.clearCanvas)
|
||||
bus.$on('onSubjectChange', this.editPanelInit)
|
||||
bus.$on('editSave', this.mobileLayoutSave)
|
||||
this.scale = this.canvasStyleData.scale
|
||||
this.mobileLayoutInitStatus = this.mobileLayoutStatus
|
||||
this.showGridSwitch = this.canvasStyleData.aidedDesign.showGrid
|
||||
@ -350,6 +351,7 @@ export default {
|
||||
this.autoCache()
|
||||
},
|
||||
beforeDestroy() {
|
||||
bus.$off('editSave', this.mobileLayoutSave)
|
||||
eventBus.$off('preview', this.preview)
|
||||
eventBus.$off('checkAndSave', this.checkAndSave)
|
||||
eventBus.$off('clearCanvas', this.clearCanvas)
|
||||
@ -654,13 +656,14 @@ export default {
|
||||
openMobileLayout(switchVal) {
|
||||
if (switchVal) {
|
||||
this.$store.commit('openMobileLayout')
|
||||
bus.$emit('mobile-status-change', 'openMobileLayout', this.componentData)
|
||||
} else {
|
||||
this.mobileLayoutSave()
|
||||
}
|
||||
},
|
||||
editSave() {
|
||||
if (this.mobileLayoutStatus) {
|
||||
this.mobileLayoutSave()
|
||||
bus.$emit('mobile-status-change', 'editSave')
|
||||
} else {
|
||||
this.saveLinkage()
|
||||
}
|
||||
@ -669,6 +672,9 @@ export default {
|
||||
this.$store.commit('setComponentData', JSON.parse(this.componentDataCache))
|
||||
this.$store.commit('setMobileLayoutStatus', false)
|
||||
this.$store.commit('openMobileLayout')
|
||||
if (this.mobileLayoutStatus) {
|
||||
bus.$emit('mobile-status-change', 'reset', JSON.parse(this.componentDataCache))
|
||||
}
|
||||
},
|
||||
editCancel() {
|
||||
if (this.mobileLayoutStatus) {
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
:style="getComponentStyleDefault(config.style)"
|
||||
style="overflow: hidden"
|
||||
:out-style="config.style"
|
||||
:terminal="terminal"
|
||||
:is-relation="isRelation"
|
||||
:element="config"
|
||||
:in-screen="inScreen"
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
<script>
|
||||
|
||||
import { mapState } from 'vuex'
|
||||
import bus from '@/utils/bus'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@ -29,7 +30,8 @@ export default {
|
||||
computed: {
|
||||
...mapState([
|
||||
'pcComponentData',
|
||||
'pcComponentGap'
|
||||
'pcComponentGap',
|
||||
'mobileLayoutStatus'
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
@ -49,6 +51,7 @@ export default {
|
||||
this.element.y = 200
|
||||
this.element.auxiliaryMatrix = true
|
||||
this.$store.commit('addComponent', { component: this.element })
|
||||
bus.$emit('mobile-status-change', 'addComponent', { component: this.element })
|
||||
} else {
|
||||
this.deleteComponent()
|
||||
}
|
||||
@ -58,6 +61,9 @@ export default {
|
||||
this.$emit('amRemoveItem')
|
||||
this.$store.commit('deleteComponentWithId', this.element.id)
|
||||
this.$store.commit('setCurComponent', { component: null, index: null })
|
||||
if (this.mobileLayoutStatus) {
|
||||
window.top.postMessage({ type: 'deleteComponentWithId', value: this.element.id }, '*')
|
||||
}
|
||||
},
|
||||
updateMobileSelected(id, mobileSelected) {
|
||||
this.pcComponentData.forEach(item => {
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
ref="deOutWidget"
|
||||
:canvas-id="canvasId"
|
||||
class="component-custom"
|
||||
:terminal="terminal"
|
||||
:out-style="element.style"
|
||||
:is-relation="isRelation"
|
||||
:element="element"
|
||||
@ -101,6 +102,10 @@ export default {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
terminal: {
|
||||
type: String,
|
||||
default: 'pc'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@ -1,34 +1,67 @@
|
||||
<template>
|
||||
<el-date-picker
|
||||
v-if="element.options!== null && element.options.attrs!==null && show"
|
||||
ref="dateRef"
|
||||
v-model="values"
|
||||
:popper-class="'coustom-date-picker' + ' ' + extPoperClass"
|
||||
:type="componentType"
|
||||
:range-separator="$t(element.options.attrs.rangeSeparator)"
|
||||
:start-placeholder="$t(element.options.attrs.startPlaceholder)"
|
||||
:end-placeholder="$t(element.options.attrs.endPlaceholder)"
|
||||
:placeholder="$t(element.options.attrs.placeholder)"
|
||||
:append-to-body="inScreen"
|
||||
value-format="timestamp"
|
||||
:format="labelFormat"
|
||||
:size="size"
|
||||
:editable="false"
|
||||
:picker-options="pickerOptions"
|
||||
:default-time="defaultRangeTime"
|
||||
@change="dateChange"
|
||||
@focus="toFocus"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
<div class="date-picker-vant">
|
||||
<el-date-picker
|
||||
v-if="element.options!== null && element.options.attrs!==null && show"
|
||||
ref="dateRef"
|
||||
v-model="values"
|
||||
:popper-class="'coustom-date-picker' + ' ' + extPoperClass"
|
||||
:type="componentType"
|
||||
:range-separator="$t(element.options.attrs.rangeSeparator)"
|
||||
:start-placeholder="$t(element.options.attrs.startPlaceholder)"
|
||||
:end-placeholder="$t(element.options.attrs.endPlaceholder)"
|
||||
:placeholder="$t(element.options.attrs.placeholder)"
|
||||
:append-to-body="inScreen"
|
||||
value-format="timestamp"
|
||||
:format="labelFormat"
|
||||
:size="size"
|
||||
:editable="false"
|
||||
:picker-options="pickerOptions"
|
||||
:default-time="defaultRangeTime"
|
||||
@change="dateChange"
|
||||
@focus="toFocus"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
<div v-if="isMobileStatus" class="vant-mobile" :class="isRange && 'wl50'" @click="showPopup"/>
|
||||
<div v-if="isMobileStatus && isRange" class="vant-mobile" :class="['datetimerange', 'datetime', 'daterange'].includes(componentType) && 'wr50'" @click="showPopupRight"/>
|
||||
<van-popup get-container="body" v-if="isMobileStatus" v-model="showDate" position="bottom" style="height: auto">
|
||||
<van-datetime-picker
|
||||
v-if="showdDatetimePicker"
|
||||
@confirm="confirm"
|
||||
@cancel="cancel"
|
||||
v-model="currentDate"
|
||||
:type="componentTypeVant"
|
||||
title="选择时间"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
/>
|
||||
<van-picker
|
||||
v-else
|
||||
title="选择时间"
|
||||
:default-index="defaultIndex"
|
||||
show-toolbar
|
||||
:columns="columns"
|
||||
@confirm="onConfirm"
|
||||
@cancel="onCancel"
|
||||
/>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ApplicationContext } from '@/utils/ApplicationContext'
|
||||
import { timeSection } from '@/utils'
|
||||
import bus from '@/utils/bus'
|
||||
import customInput from '@/components/widget/deWidget/customInput'
|
||||
import customInput from '@/components/widget/deWidget/customInput'
|
||||
import { dateMap, years, seconds } from '@/components/widget/deWidget/serviceNameFn'
|
||||
import { mapState } from 'vuex'
|
||||
import vanPopup from 'vant/lib/popup'
|
||||
import vanDatetimePicker from 'vant/lib/datetime-picker'
|
||||
import vanPicker from 'vant/lib/picker'
|
||||
import 'vant/lib/popup/style'
|
||||
import 'vant/lib/datetime-picker/style'
|
||||
import 'vant/lib/picker/style'
|
||||
export default {
|
||||
components: { vanPopup, vanDatetimePicker, vanPicker },
|
||||
mixins: [customInput],
|
||||
props: {
|
||||
canvasId: {
|
||||
@ -52,19 +85,60 @@ export default {
|
||||
isRelation: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
terminal: {
|
||||
type: String,
|
||||
default: 'pc'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showDate: false,
|
||||
minDate: new Date(1980, 0, 1),
|
||||
maxDate: new Date(2025, 10, 1),
|
||||
currentDate: new Date(),
|
||||
operator: 'between',
|
||||
defaultIndex: 2,
|
||||
columns: years,
|
||||
values: null,
|
||||
onFocus: false,
|
||||
show: true,
|
||||
selectSecondInput: false,
|
||||
selectSecond: false,
|
||||
outTimer: null,
|
||||
innerTimer: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isMobileStatus() {
|
||||
return this.mobileStatus || this.terminal === 'mobile'
|
||||
},
|
||||
isRange() {
|
||||
if (!this.isMobileStatus) return false
|
||||
return ['datetimerange', 'daterange'].includes(this.componentType)
|
||||
},
|
||||
showdDatetimePicker() {
|
||||
if (!this.isMobileStatus) return false
|
||||
if (this.showSecond && this.selectSecond) return false
|
||||
return this.componentTypeVant !== 'year'
|
||||
},
|
||||
showSecond() {
|
||||
if (!this.isMobileStatus) return false
|
||||
return this.labelFormat?.endsWith('ss')
|
||||
},
|
||||
componentTypeVant() {
|
||||
if (!this.isMobileStatus) return ''
|
||||
if (this.showSecond) {
|
||||
return 'datetime'
|
||||
}
|
||||
if (this.labelFormat?.endsWith('mm')) {
|
||||
return 'datetime'
|
||||
}
|
||||
if (this.labelFormat?.endsWith('HH')) {
|
||||
return 'datehour'
|
||||
}
|
||||
return dateMap[this.componentType]
|
||||
},
|
||||
extPoperClass() {
|
||||
if (this.labelFormat && this.labelFormat.includes('HH') && !this.labelFormat.includes('HH:mm')) {
|
||||
return 'de-no-minite'
|
||||
@ -130,7 +204,8 @@ export default {
|
||||
return null
|
||||
},
|
||||
...mapState([
|
||||
'canvasStyleData'
|
||||
'canvasStyleData',
|
||||
'mobileStatus'
|
||||
])
|
||||
|
||||
},
|
||||
@ -186,6 +261,86 @@ export default {
|
||||
bus.$off('reset-default-value', this.resetDefaultValue)
|
||||
},
|
||||
methods: {
|
||||
showPopupRight() {
|
||||
const [_, end] = this.values || []
|
||||
!!end && (this.currentDate = new Date(end))
|
||||
this.selectSecondInput = true
|
||||
this.showDate = true
|
||||
},
|
||||
cancel() {
|
||||
this.showDate = false
|
||||
},
|
||||
confirm() {
|
||||
this.setArrValue()
|
||||
if (this.showSecond) {
|
||||
this.columns = seconds
|
||||
this.selectSecond = true
|
||||
}
|
||||
if (this.selectSecond || this.componentTypeVant === 'year') {
|
||||
return
|
||||
}
|
||||
this.showDate = false
|
||||
this.mobileDateChange()
|
||||
},
|
||||
onCancel() {
|
||||
this.showDate = false
|
||||
if (this.showSecond) {
|
||||
this.selectSecond = false
|
||||
}
|
||||
},
|
||||
setArrValue(val) {
|
||||
if (!this.isRange) {
|
||||
if (this.selectSecond) {
|
||||
this.values = this.values + val * 1000
|
||||
return
|
||||
}
|
||||
this.values = val ? +new Date(val) : +new Date(this.currentDate)
|
||||
return
|
||||
}
|
||||
const [start, end] = this.values || []
|
||||
if (this.selectSecond) {
|
||||
if (this.selectSecondInput) {
|
||||
this.values = [start, +new Date(this.currentDate) + val * 1000]
|
||||
} else {
|
||||
this.values = [+new Date(this.currentDate) + val * 1000, end]
|
||||
}
|
||||
return
|
||||
}
|
||||
if (this.selectSecondInput) {
|
||||
this.values = [start, +new Date(this.currentDate)]
|
||||
} else {
|
||||
this.values = [+new Date(this.currentDate), end]
|
||||
}
|
||||
},
|
||||
onConfirm(val) {
|
||||
this.showDate = false
|
||||
this.setArrValue(val)
|
||||
if (this.showSecond) {
|
||||
this.columns = years
|
||||
this.selectSecond = false
|
||||
}
|
||||
this.mobileDateChange()
|
||||
},
|
||||
mobileDateChange() {
|
||||
if (this.isRange) {
|
||||
const [start, end] = this.values || []
|
||||
if (!start || !end) return
|
||||
}
|
||||
this.dateChange(this.values)
|
||||
},
|
||||
showPopup() {
|
||||
if (this.isRange) {
|
||||
const [start] = this.values || []
|
||||
!!start && (this.currentDate = new Date(start))
|
||||
} else {
|
||||
this.currentDate = new Date(this.values)
|
||||
if (this.componentTypeVant === 'year') {
|
||||
this.defaultIndex = years.findIndex(ele => `${this.currentDate.getFullYear()}` === ele)
|
||||
}
|
||||
}
|
||||
this.selectSecondInput = false
|
||||
this.showDate = true
|
||||
},
|
||||
loadInit() {
|
||||
this.clearTime()
|
||||
if (this.refreshHandler()) {
|
||||
@ -340,6 +495,28 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.date-picker-vant {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
.el-date-editor {
|
||||
width: 100% !important;
|
||||
}
|
||||
.vant-mobile {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
&.wl50 {
|
||||
width: 50%;
|
||||
}
|
||||
&.wr50 {
|
||||
left: auto;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.coustom-date-picker {
|
||||
right: 0px;
|
||||
border: 1px solid var(--BrDateColor, #dfe4ed) !important;
|
||||
|
||||
@ -79,6 +79,18 @@ function handlerInputStyle(node, style) {
|
||||
})
|
||||
}
|
||||
|
||||
const dateMap = {
|
||||
year: 'year',
|
||||
month: 'year-month',
|
||||
date: 'date',
|
||||
datetime: 'datetime',
|
||||
datetimerange: 'datetime',
|
||||
daterange: 'date'
|
||||
}
|
||||
|
||||
const years = Array(60).fill(1).map((_, index) => `${index + 1980}`)
|
||||
const seconds = Array(60).fill(1).map((_, index) => index)
|
||||
|
||||
export {
|
||||
attrsMap,
|
||||
styleAttrs,
|
||||
@ -87,5 +99,8 @@ export {
|
||||
textSelectGridWidget,
|
||||
textSelectTreeWidget,
|
||||
textSelectWidget,
|
||||
handlerInputStyle
|
||||
handlerInputStyle,
|
||||
dateMap,
|
||||
years,
|
||||
seconds
|
||||
}
|
||||
|
||||
9
core/frontend/src/mobile/App.vue
Normal file
9
core/frontend/src/mobile/App.vue
Normal file
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AppMobile'
|
||||
}
|
||||
</script>
|
||||
155
core/frontend/src/mobile/main.js
Normal file
155
core/frontend/src/mobile/main.js
Normal file
@ -0,0 +1,155 @@
|
||||
import Vue from 'vue'
|
||||
import Cookies from 'js-cookie'
|
||||
import '@/styles/index.scss' // global css
|
||||
import ElementUI from 'element-ui'
|
||||
import Vuetify from 'vuetify'
|
||||
import Fit2CloudUI from 'fit2cloud-ui'
|
||||
|
||||
import i18n from '../lang' // internationalization
|
||||
import App from './App'
|
||||
import store from '../store'
|
||||
import router from '../router/mobile.js'
|
||||
import message from '../utils/message'
|
||||
import '@/icons' // icon
|
||||
import '@/permission' // permission control
|
||||
import api from '@/api/index.js'
|
||||
import filter from '@/filter/filter'
|
||||
import directives from '../directive'
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
import widgets from '@/components/widget'
|
||||
import Treeselect from '@riophae/vue-treeselect'
|
||||
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
|
||||
import '../utils/dialog'
|
||||
import DeComplexInput from '@/components/business/conditionTable/DeComplexInput'
|
||||
import DeComplexSelect from '@/components/business/conditionTable/DeComplexSelect'
|
||||
import DeViewSelect from '@/components/deViewSelect'
|
||||
import RemarkEditor from '@/views/chart/components/componentStyle/dialog/RemarkEditor'
|
||||
import TitleRemark from '@/views/chart/view/TitleRemark'
|
||||
import '@/components/canvas/customComponent' // 注册自定义组件
|
||||
import deBtn from '@/components/deCustomCm/DeBtn.vue'
|
||||
|
||||
import '@/utils/DateUtil'
|
||||
import draggable from 'vuedraggable'
|
||||
import deWebsocket from '@/websocket'
|
||||
import { GaodeMap } from '@antv/l7-maps'
|
||||
import * as echarts from 'echarts'
|
||||
import UmyUi from 'umy-ui'
|
||||
// 全屏插件
|
||||
import fullscreen from 'vue-fullscreen'
|
||||
import VueFriendlyIframe from 'vue-friendly-iframe'
|
||||
import vueToPdf from 'vue-to-pdf'
|
||||
import VueVideoPlayer from 'vue-video-player'
|
||||
import 'video.js/dist/video-js.css'
|
||||
import '@antv/s2/dist/style.min.css'
|
||||
// 控制标签宽高成比例的指令
|
||||
import proportion from 'vue-proportion-directive'
|
||||
|
||||
import xss from 'xss'
|
||||
// 定义全局XSS解决方法
|
||||
Object.defineProperty(Vue.prototype, '$xss', {
|
||||
value: xss
|
||||
})
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.use(VueClipboard)
|
||||
Vue.use(widgets)
|
||||
Vue.component('Draggable', draggable)
|
||||
Vue.prototype.$api = api
|
||||
|
||||
Vue.prototype.$echarts = echarts
|
||||
Vue.prototype.$gaodeMap = GaodeMap
|
||||
|
||||
Vue.use(UmyUi)
|
||||
|
||||
Vue.use(fullscreen)
|
||||
|
||||
Vue.use(VueFriendlyIframe)
|
||||
Vue.use(Vuetify)
|
||||
// import TEditor from '@/components/Tinymce/index.vue'
|
||||
// Vue.component('TEditor', TEditor)
|
||||
|
||||
/**
|
||||
* If you don't want to use mock-server
|
||||
* you want to use MockJs for mock api
|
||||
* you can execute: mockXHR()
|
||||
*
|
||||
* Currently MockJs will be used in the production environment,
|
||||
* please remove it before going online ! ! !
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// const { mockXHR } = require('.../mock')
|
||||
// mockXHR()
|
||||
}
|
||||
|
||||
// set ElementUI lang to EN
|
||||
// Vue.use(ElementUI, { locale })
|
||||
// 如果想要中文版 element-ui,按如下方式声明
|
||||
ElementUI.Dialog.props.closeOnClickModal.default = false
|
||||
ElementUI.Dialog.props.closeOnPressEscape.default = false
|
||||
Vue.use(ElementUI, {
|
||||
size: Cookies.get('size') || 'medium', // set element-ui default size
|
||||
i18n: (key, value) => i18n.t(key, value)
|
||||
})
|
||||
Vue.use(Fit2CloudUI, {
|
||||
i18n: (key, value) => i18n.t(key, value)
|
||||
})
|
||||
// Vue.use(VueAxios, axios)
|
||||
Vue.use(filter)
|
||||
Vue.use(directives)
|
||||
Vue.use(message)
|
||||
Vue.component('Treeselect', Treeselect)
|
||||
Vue.component('DeComplexInput', DeComplexInput)
|
||||
Vue.component('DeComplexSelect', DeComplexSelect)
|
||||
Vue.component('DeViewSelect', DeViewSelect)
|
||||
Vue.component('RemarkEditor', RemarkEditor)
|
||||
Vue.component('TitleRemark', TitleRemark)
|
||||
Vue.component('DeBtn', deBtn)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Vue.use(vueToPdf)
|
||||
|
||||
Vue.use(VueVideoPlayer)
|
||||
|
||||
Vue.use(proportion)
|
||||
|
||||
Vue.prototype.hasDataPermission = function(pTarget, pSource) {
|
||||
if (this.$store.state.user.user.isAdmin || pSource === 'ignore') {
|
||||
return true
|
||||
}
|
||||
if (pSource && pTarget) {
|
||||
return pSource.indexOf(pTarget) > -1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Vue.prototype.checkPermission = function(pers) {
|
||||
const permissions = store.getters.permissions
|
||||
const hasPermission = pers.every(needP => {
|
||||
const result = permissions.includes(needP)
|
||||
return result
|
||||
})
|
||||
return hasPermission
|
||||
}
|
||||
Vue.use(deWebsocket)
|
||||
|
||||
Vue.prototype.$currentHttpRequestList = new Map()
|
||||
Vue.prototype.$cancelRequest = function(cancelkey) {
|
||||
if (cancelkey) {
|
||||
if (cancelkey.indexOf('/**') > -1) {
|
||||
Vue.prototype.$currentHttpRequestList.forEach((item, key) => {
|
||||
key.indexOf(cancelkey.split('/**')[0]) > -1 && item('Operation canceled by the user.')
|
||||
})
|
||||
} else {
|
||||
Vue.prototype.$currentHttpRequestList.get(cancelkey) && Vue.prototype.$currentHttpRequestList.get(cancelkey)('Operation canceled by the user.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
|
||||
router,
|
||||
store,
|
||||
i18n,
|
||||
render: h => h(App)
|
||||
}).$mount('#app-mobile')
|
||||
19
core/frontend/src/router/mobile.js
Normal file
19
core/frontend/src/router/mobile.js
Normal file
@ -0,0 +1,19 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
|
||||
Vue.use(Router)
|
||||
export const constantRoutes = [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('@/views/mobile/index.vue'),
|
||||
}
|
||||
]
|
||||
|
||||
const createRouter = () => new Router({
|
||||
mode: 'hash',
|
||||
scrollBehavior: () => ({ y: 0 }),
|
||||
routes: constantRoutes
|
||||
})
|
||||
|
||||
const router = createRouter()
|
||||
export default router
|
||||
@ -92,6 +92,8 @@ const data = {
|
||||
componentGap: 5,
|
||||
// 移动端布局状态
|
||||
mobileLayoutStatus: false,
|
||||
// 是否是mobile
|
||||
mobileStatus: false,
|
||||
// 公共链接状态(当前是否是公共链接打开)
|
||||
publicLinkStatus: false,
|
||||
pcTabMatrixCount: {
|
||||
@ -574,6 +576,9 @@ const data = {
|
||||
setMobileLayoutStatus(state, status) {
|
||||
state.mobileLayoutStatus = status
|
||||
},
|
||||
setMobileStatus(state, status) {
|
||||
state.mobileStatus = status
|
||||
},
|
||||
setPublicLinkStatus(state, status) {
|
||||
state.publicLinkStatus = status
|
||||
},
|
||||
|
||||
142
core/frontend/src/views/mobile/index.vue
Normal file
142
core/frontend/src/views/mobile/index.vue
Normal file
@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<el-row
|
||||
id="canvasInfoMobile"
|
||||
class="this_mobile_canvas_main"
|
||||
:style="mobileCanvasStyle"
|
||||
>
|
||||
<canvas-opt-bar/>
|
||||
<de-canvas
|
||||
ref="canvasMainRef"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:component-data="mainCanvasComponentData"
|
||||
:canvas-id="canvasId"
|
||||
:canvas-pid="'0'"
|
||||
:mobile-layout-status="true"
|
||||
/>
|
||||
</el-row>
|
||||
</template>
|
||||
<script>
|
||||
import DeCanvas from '@/components/canvas/DeCanvas'
|
||||
import CanvasOptBar from '@/components/canvas/components/editor/CanvasOptBar'
|
||||
import {
|
||||
imgUrlTrans,
|
||||
getNowCanvasComponentData,
|
||||
} from "@/components/canvas/utils/utils";
|
||||
import { mapState } from "vuex";
|
||||
import { hexColorToRGBA } from "@/views/chart/chart/util";
|
||||
export default {
|
||||
components: { DeCanvas, CanvasOptBar },
|
||||
data() {
|
||||
return {
|
||||
canvasId: "canvas-main",
|
||||
previewVisible: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["canvasStyleData", "mobileLayoutStatus", 'componentData']),
|
||||
mainCanvasComponentData() {
|
||||
return getNowCanvasComponentData(this.canvasId);
|
||||
},
|
||||
mobileCanvasStyle() {
|
||||
let style;
|
||||
if (this.canvasStyleData.openCommonStyle) {
|
||||
const styleInfo =
|
||||
this.canvasStyleData.panel.mobileSetting &&
|
||||
this.canvasStyleData.panel.mobileSetting.customSetting
|
||||
? this.canvasStyleData.panel.mobileSetting
|
||||
: this.canvasStyleData.panel;
|
||||
if (
|
||||
styleInfo.backgroundType === "image" &&
|
||||
typeof styleInfo.imageUrl === "string"
|
||||
) {
|
||||
style = {
|
||||
background: `url(${imgUrlTrans(styleInfo.imageUrl)}) no-repeat`,
|
||||
};
|
||||
} else if (styleInfo.backgroundType === "color") {
|
||||
const colorRGBA = hexColorToRGBA(
|
||||
styleInfo.color,
|
||||
styleInfo.alpha === undefined ? 100 : styleInfo.alpha,
|
||||
);
|
||||
style = {
|
||||
background: colorRGBA,
|
||||
};
|
||||
} else {
|
||||
style = {
|
||||
background: "#f7f8fa",
|
||||
};
|
||||
}
|
||||
}
|
||||
return style;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.commit('setMobileLayoutStatus', true)
|
||||
this.$store.commit('setMobileStatus', true)
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.type === 'addComponent') {
|
||||
this.$store.commit('addComponent', event.data.value)
|
||||
}
|
||||
if (event.data.type === 'setCanvasStyle') {
|
||||
this.$store.commit('setCanvasStyle', event.data.value)
|
||||
}
|
||||
if (event.data.type === 'editSave') {
|
||||
window.top.postMessage({ type: 'setComponentData', value: this.componentData }, '*')
|
||||
}
|
||||
if (event.data.type === 'reset') {
|
||||
this.$store.commit('setComponentData', event.data.value)
|
||||
this.$store.commit('openMobileLayout')
|
||||
}
|
||||
|
||||
if (event.data.type === 'openMobileLayout') {
|
||||
this.$store.commit('setComponentData', event.data.value)
|
||||
this.$store.commit('openMobileLayout')
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
this.show = false
|
||||
},
|
||||
confirm() {
|
||||
this.show = false
|
||||
},
|
||||
showPopup() {
|
||||
this.show = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.this_mobile_canvas_main {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
background-size: 100% 100% !important;
|
||||
}
|
||||
.mobile-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
color: #323233;
|
||||
font-size: 16px;
|
||||
font-family:
|
||||
"Open Sans",
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Helvetica Neue",
|
||||
Helvetica,
|
||||
Segoe UI,
|
||||
Arial,
|
||||
Roboto,
|
||||
"PingFang SC",
|
||||
"miui",
|
||||
"Hiragino Sans GB",
|
||||
"Microsoft Yahei",
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
height: 570px;
|
||||
box-sizing: border-box;
|
||||
width: 360px;
|
||||
min-width: 360px;
|
||||
overflow: hidden;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
@ -47,7 +47,7 @@ import { mapState } from 'vuex'
|
||||
import ComponentWaitItem from '@/views/panel/edit/ComponentWaitItem'
|
||||
import MobileBackgroundSelector from '@/views/panel/subjectSetting/panelStyle/MobileBackgroundSelector'
|
||||
import { imgUrlTrans } from '@/components/canvas/utils/utils'
|
||||
import {hexColorToRGBA} from "@/views/chart/chart/util";
|
||||
import { hexColorToRGBA } from '@/views/chart/chart/util'
|
||||
|
||||
export default {
|
||||
name: 'ComponentWait',
|
||||
|
||||
@ -188,7 +188,7 @@
|
||||
class="mobile_canvas_main"
|
||||
>
|
||||
<el-col
|
||||
:span="8"
|
||||
:span="10"
|
||||
class="this_mobile_canvas_cell"
|
||||
>
|
||||
<div
|
||||
@ -200,23 +200,8 @@
|
||||
<el-row class="this_mobile_canvas_inner_top">
|
||||
{{ panelInfo.name }}
|
||||
</el-row>
|
||||
<el-row class="this_mobile_canvas_main_outer">
|
||||
<el-row
|
||||
id="canvasInfoMobile"
|
||||
class="this_mobile_canvas_main"
|
||||
:style="mobileCanvasStyle"
|
||||
>
|
||||
<canvas-opt-bar v-if="!previewVisible&&mobileLayoutStatus"/>
|
||||
<de-canvas
|
||||
v-if="!previewVisible&&mobileLayoutStatus"
|
||||
ref="canvasMainRef"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:component-data="mainCanvasComponentData"
|
||||
:canvas-id="canvasId"
|
||||
:canvas-pid="'0'"
|
||||
:mobile-layout-status="true"
|
||||
/>
|
||||
</el-row>
|
||||
<el-row v-loading="mobileLoading" class="this_mobile_canvas_main_outer">
|
||||
<iframe src="./mobile.html" @load="handleLoad" frameborder="0" width="360" height="570"></iframe>
|
||||
</el-row>
|
||||
<el-row class="this_mobile_canvas_inner_bottom">
|
||||
<el-col :span="12">
|
||||
@ -249,7 +234,7 @@
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col
|
||||
:span="16"
|
||||
:span="14"
|
||||
class="this_mobile_canvas_cell this_mobile_canvas_wait_cell"
|
||||
>
|
||||
<component-wait/>
|
||||
@ -593,6 +578,7 @@ export default {
|
||||
autoMoveOffSet: 15,
|
||||
mobileEditorShow: true,
|
||||
hasStar: false,
|
||||
mobileLoading: true,
|
||||
drawerSize: '300px',
|
||||
visible: false,
|
||||
show: false,
|
||||
@ -652,7 +638,7 @@ export default {
|
||||
{ label: '适应新主题', value: true },
|
||||
{ label: '保持源样式', value: false }
|
||||
],
|
||||
multiplexingStyleAdaptSelf : true
|
||||
multiplexingStyleAdaptSelf: true
|
||||
}
|
||||
},
|
||||
|
||||
@ -776,7 +762,7 @@ export default {
|
||||
curCanvasScaleSelf() {
|
||||
return this.curCanvasScaleMap[this.canvasId]
|
||||
},
|
||||
selectComponentCount(){
|
||||
selectComponentCount() {
|
||||
return Object.keys(this.curMultiplexingComponents).length
|
||||
},
|
||||
...mapState([
|
||||
@ -786,6 +772,7 @@ export default {
|
||||
'canvasStyleData',
|
||||
'curComponentIndex',
|
||||
'componentData',
|
||||
'pcComponentData',
|
||||
'linkageSettingStatus',
|
||||
'dragComponentInfo',
|
||||
'componentGap',
|
||||
@ -817,7 +804,8 @@ export default {
|
||||
this.recordStyleChange(this.$store.state.styleChangeTimes)
|
||||
}
|
||||
},
|
||||
mobileLayoutStatus() {
|
||||
mobileLayoutStatus(val) {
|
||||
this.mobileLoading = val
|
||||
this.restore()
|
||||
},
|
||||
previewVisible(val) {
|
||||
@ -849,6 +837,21 @@ export default {
|
||||
listenGlobalKeyDown()
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('mobile-status-change', this.mobileStatusChange)
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.type === 'deleteComponentWithId') {
|
||||
console.log('event1', event.data)
|
||||
this.$store.commit('deleteComponentWithId', event.data.value)
|
||||
this.deleteComponentWithId(event.data.value)
|
||||
}
|
||||
if (event.data.type === 'setComponentData') {
|
||||
console.log('setComponentData', event.data)
|
||||
this.$store.commit('setComponentData', event.data.value)
|
||||
setTimeout(() => {
|
||||
bus.$emit('editSave')
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
this.initWatermark()
|
||||
this.initEvents()
|
||||
const _this = this
|
||||
@ -864,6 +867,7 @@ export default {
|
||||
this.multiplexingStyleAdaptSelf = this.multiplexingStyleAdapt
|
||||
},
|
||||
beforeDestroy() {
|
||||
bus.$off('mobile-status-change', this.mobileStatusChange)
|
||||
bus.$off('component-on-drag', this.componentOnDrag)
|
||||
bus.$off('component-dialog-style', this.componentDialogStyle)
|
||||
bus.$off('previewFullScreenClose', this.previewFullScreenClose)
|
||||
@ -875,6 +879,40 @@ export default {
|
||||
elx && elx.remove()
|
||||
},
|
||||
methods: {
|
||||
handleLoad() {
|
||||
this.mobileLoading = false
|
||||
this.mobileStatusChange('openMobileLayout', this.componentData)
|
||||
},
|
||||
deleteComponentWithId(id) {
|
||||
for (let index = 0; index < this.pcComponentData.length; index++) {
|
||||
const element = this.pcComponentData[index]
|
||||
if (element.id && element.id === id) {
|
||||
element.mobileSelected = false
|
||||
if (element.type === 'de-tabs') {
|
||||
this.deleteComponentWithId(element.id)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
mobileStatusChange(type, value) {
|
||||
console.log('mobileLayoutStatustype', type, this.mobileLayoutStatus)
|
||||
if (!this.mobileLayoutStatus) return
|
||||
const iframe = document.querySelector('iframe')
|
||||
console.log('iframe', iframe)
|
||||
if (iframe) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{
|
||||
type,
|
||||
value
|
||||
},
|
||||
'*'
|
||||
)
|
||||
}
|
||||
// if (['setCanvasStyle', 'addComponent'].includes(type)) {
|
||||
|
||||
// }
|
||||
},
|
||||
initWatermark() {
|
||||
if (this.panelInfo.watermarkInfo) {
|
||||
this.$nextTick(() => {
|
||||
@ -1557,14 +1595,14 @@ export default {
|
||||
.mobile_canvas_main {
|
||||
width: 80%;
|
||||
height: 90%;
|
||||
margin-left: 10%;
|
||||
margin-left: 7%;
|
||||
margin-top: 3%;
|
||||
}
|
||||
|
||||
.this_mobile_canvas {
|
||||
border-radius: 30px;
|
||||
min-width: 300px;
|
||||
max-width: 350px;
|
||||
min-width: 370px;
|
||||
max-width: 370px;
|
||||
min-height: 600px;
|
||||
max-height: 700px;
|
||||
overflow: hidden;
|
||||
|
||||
@ -106,6 +106,7 @@ import { mapState } from 'vuex'
|
||||
import { deepCopy, imgUrlTrans } from '@/components/canvas/utils/utils'
|
||||
import { COLOR_PANEL } from '@/views/chart/chart/chart'
|
||||
import { uploadFileResult } from '@/api/staticResource/staticResource'
|
||||
import bus from '@/utils/bus'
|
||||
|
||||
export default {
|
||||
name: 'MobileBackgroundSelector',
|
||||
@ -141,6 +142,7 @@ export default {
|
||||
const canvasStyleData = deepCopy(this.canvasStyleData)
|
||||
canvasStyleData.panel.mobileSetting = this.mobileSetting
|
||||
this.$store.commit('setCanvasStyle', canvasStyleData)
|
||||
bus.$emit('mobile-status-change', 'setCanvasStyle', canvasStyleData)
|
||||
this.$store.commit('recordSnapshot', 'commitStyle')
|
||||
},
|
||||
onChangeType() {
|
||||
|
||||
@ -41,6 +41,11 @@ module.exports = {
|
||||
entry: 'src/main.js',
|
||||
template: 'public/index.html',
|
||||
filename: 'index.html'
|
||||
},
|
||||
mobile: {
|
||||
entry: 'src/mobile/main.js',
|
||||
template: 'public/mobile.html',
|
||||
filename: 'mobile.html'
|
||||
}
|
||||
},
|
||||
configureWebpack: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user