1186 lines
34 KiB
Vue
1186 lines
34 KiB
Vue
<template>
|
||
<div class="layout" @click.prevent="isShowMenu = false, activeIndex = -1"
|
||
@contextmenu.prevent="isShowMenu = false, activeIndex = -1">
|
||
<div class="layout-header">
|
||
<div class="layout-header__left"></div>
|
||
<div class="layout-header__middle">
|
||
<h2>{{ dashboard.title }}</h2>
|
||
</div>
|
||
<div class="layout-header__right">
|
||
<span type="text" @click="isShowImg = true">图片素材</span>
|
||
<span type="text" @click="back">退出</span>
|
||
<span type="text" @click="save">保存</span>
|
||
</div>
|
||
</div>
|
||
<div class="layout-wrapper">
|
||
<div class="layout-left">
|
||
<h2>全部资产</h2>
|
||
<div class="layout-left__wrapper">
|
||
<div class="layout-left__left">
|
||
<div @click="subIndex = 0, parentIndex = index" :class="parentIndex === index ? 'active' : ''"
|
||
v-for="(item, index) in components" :key="index">
|
||
<i class="iconfont iconqiyeguanli"></i>
|
||
<span>{{ item.label }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="layout-left__middle">
|
||
<div>全部</div>
|
||
<div
|
||
class="layout-left__middle--item"
|
||
:class="subIndex === index ? 'active' : ''"
|
||
@click="subIndex = index"
|
||
v-for="(item, index) in components[parentIndex].list"
|
||
:key="index">
|
||
{{ item.label }}
|
||
</div>
|
||
</div>
|
||
<div class="layout-left__right">
|
||
<div class="layout-left__right--item" v-for="(item, index) in widget" @click="clone(item)" :key="index">
|
||
<span class="tools-item-text">{{ item.label }}</span>
|
||
<img :src="item.thumb"/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layout-middle">
|
||
<div class="canvas-wrapper">
|
||
<vue-ruler-tool
|
||
v-model="dashboard.presetLine"
|
||
class="vueRuler"
|
||
:step-length="50"
|
||
:parent="true"
|
||
:position="'relative'"
|
||
:is-scale-revise="true"
|
||
:visible.sync="dashboard.presetLineVisible">
|
||
<div
|
||
id="workbench"
|
||
class="workbench"
|
||
:style="{
|
||
transform: workbenchTransform,
|
||
width: bigscreenWidth + 'px',
|
||
height: bigscreenHeight + 'px'
|
||
}">
|
||
<ai-dv-wrapper style="height: 100%" :title="params.name">
|
||
<div style="width: 100%; height: 100%">
|
||
<AiDvBackground
|
||
v-if="dashboard.backgroundImage.length"
|
||
:src="dashboard.backgroundImage[0].url">
|
||
</AiDvBackground>
|
||
<vue-draggable-resizable
|
||
:w="item.width"
|
||
:h="item.height"
|
||
:x="item.left"
|
||
:y="item.top"
|
||
:scale="heightScale"
|
||
:z="item.zIndex || 0"
|
||
:parent="true"
|
||
:resizable="item.type !== 'display' || item.display === 'summary2' || item.display === 'summary3'"
|
||
class-name-active="drag-active"
|
||
:class="[activeIndex === index ? 'drag-active' : '']"
|
||
class="draggable"
|
||
@contextmenu.native.stop="e => onContextmenu(e, index)"
|
||
@dragging="(x, y) => onDrag(x, y, index)"
|
||
@resizing="(x, y, w, h) => onResizing(x, y, w, h, index, item.type)"
|
||
@activated="onActivated(index)"
|
||
@click.native.stop="activeIndex = index"
|
||
v-for="(item, index) in componentList"
|
||
:key="index">
|
||
<div class="coordinate" v-show="activeIndex === index">
|
||
<div class="coordinate-left"></div>
|
||
<div class="coordinate-top"></div>
|
||
<div class="coordinate-label">{{ item.left }}, {{ item.top }}</div>
|
||
</div>
|
||
<RenderElement :data="item" :index="index"></RenderElement>
|
||
</vue-draggable-resizable>
|
||
</div>
|
||
</ai-dv-wrapper>
|
||
</div>
|
||
</vue-ruler-tool>
|
||
</div>
|
||
</div>
|
||
<div class="layout-right" @click.stop>
|
||
<div class="layout-tab" v-if="activeIndex > -1">
|
||
<span @click="configIndex = 0" :class="[configIndex === 0 ? 'layout-tab__active' : '']">参数</span>
|
||
<span @click="configIndex = 1" :class="[configIndex === 1 ? 'layout-tab__active' : '']">数据</span>
|
||
</div>
|
||
<div class="layout-right__content" v-if="activeIndex > -1">
|
||
<div class="layout-right__content--wrapper" v-show="configIndex === 0">
|
||
<div class="layout-config__group">
|
||
<h2>基础设置</h2>
|
||
<div class="layout-config__item">
|
||
<label>图表尺寸</label>
|
||
<div class="layout-config__item--right">
|
||
<el-input-number size="mini" :min="0" v-model="currLayout.width"
|
||
controls-position="right"></el-input-number>
|
||
<el-input-number size="mini" :min="0" v-model="currLayout.height"
|
||
controls-position="right"></el-input-number>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item">
|
||
<label>图表位置</label>
|
||
<div class="layout-config__item--right">
|
||
<el-input-number size="mini" :min="0" v-model="currLayout.left"
|
||
controls-position="right"></el-input-number>
|
||
<el-input-number size="mini" :min="0" v-model="currLayout.top"
|
||
controls-position="right"></el-input-number>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layout-right__content--wrapper" v-show="configIndex === 0">
|
||
<div class="layout-config__group">
|
||
<h2>组件设置</h2>
|
||
<div class="layout-config__item layout-config__item--input">
|
||
<label>标题</label>
|
||
<div class="layout-config__item--right">
|
||
<el-input v-model="currLayout.title" size="mini"></el-input>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item" v-if="currLayout.type !== 'display'">
|
||
<label>边框</label>
|
||
<div class="layout-config__item--right">
|
||
<el-select size="mini" v-model="currLayout.border" placeholder="请选择边框" clearable>
|
||
<el-option
|
||
v-for="(item, index) in borderList"
|
||
:key="index"
|
||
:label="item"
|
||
:value="item">
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item" v-if="currLayout.type === 'map'">
|
||
<label>遮罩层</label>
|
||
<div class="layout-config__item--right">
|
||
<el-select size="mini" v-model="currLayout.mask" placeholder="请选择" clearable>
|
||
<el-option label="是" value="1"></el-option>
|
||
<el-option label="否" value="2"></el-option>
|
||
</el-select>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item layout-config__item--input" v-if="currLayout.type === 'video'">
|
||
<label>视频地址</label>
|
||
<div class="layout-config__item--right">
|
||
<el-input v-model="currLayout.src" size="mini"></el-input>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item" v-if="currLayout.type === 'monitor'">
|
||
<label>视频类型</label>
|
||
<div class="layout-config__item--right">
|
||
<el-select size="mini" v-model="currLayout.monitorType" placeholder="请选择" clearable>
|
||
<el-option label="中国移动" value="cmcc"></el-option>
|
||
<el-option label="海康威视" value="hik"></el-option>
|
||
<el-option label="大华" value="dahua"></el-option>
|
||
<el-option label="视联网" value="slw"></el-option>
|
||
</el-select>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item" v-if="currLayout.type === 'table'">
|
||
<label>显示排名</label>
|
||
<div class="layout-config__item--right">
|
||
<el-select size="mini" v-model="currLayout.isShowIndex" placeholder="请选择" clearable>
|
||
<el-option
|
||
v-for="(item, index) in tableStatus"
|
||
:key="index"
|
||
:label="item.label"
|
||
:value="item.value">
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item" v-if="currLayout.type === 'table'">
|
||
<label>表格行数</label>
|
||
<div class="layout-config__item--right">
|
||
<el-input-number size="mini" style="width: 232px" :min="0" v-model="currLayout.rowNum" controls-position="right"></el-input-number>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item" v-if="currLayout.type === 'map'">
|
||
<label>选择地区</label>
|
||
<div class="layout-config__item--right">
|
||
<AiAreaGet :instance="instance" :valueLevel="3" v-model="currLayout.areaId" placeholder="请选择地区"></AiAreaGet>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item" v-if="currLayout.type === 'summary'">
|
||
<label>数据汇总</label>
|
||
<div class="layout-config__item--right">
|
||
<el-select size="mini" v-model="currLayout.display" placeholder="请选择类型" clearable>
|
||
<el-option
|
||
v-for="(item, index) in summaryList"
|
||
:key="index"
|
||
:label="item"
|
||
:value="item">
|
||
</el-option>
|
||
</el-select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="layout-right__content--wrapper" v-show="configIndex === 1"
|
||
v-if="currLayout.type !== 'title' && currLayout.type !== 'video'">
|
||
<data-config
|
||
ref="dataConfig"
|
||
:instance="instance"
|
||
:dict="dict"
|
||
:urlPrefix="urlPrefix"
|
||
:options="currLayout"
|
||
@change="onChange('barChart')">
|
||
</data-config>
|
||
</div>
|
||
</div>
|
||
<div class="layout-page__setting layout-right__content" v-if="activeIndex === -1">
|
||
<h2>页面设置</h2>
|
||
<div class="layout-config__group">
|
||
<div class="layout-config__item">
|
||
<label>屏幕大小</label>
|
||
<div class="layout-config__item--right">
|
||
<el-input-number size="mini" :min="0" v-model="bigscreenWidth" disabled
|
||
controls-position="right"></el-input-number>
|
||
<el-input-number size="mini" :min="0" v-model="bigscreenHeight" disabled
|
||
controls-position="right"></el-input-number>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item layout-config__item--input">
|
||
<label>屏幕标题</label>
|
||
<div class="layout-config__item--right">
|
||
<el-input v-model="dashboard.title" size="mini"></el-input>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item">
|
||
<label>背景图</label>
|
||
<div class="layout-config__item--right layout-config__item--bg">
|
||
<ai-uploader v-model="dashboard.backgroundImage" :maxSize="2" :limit="1" :isShowTip="false"
|
||
:instance="instance">
|
||
<div slot="trigger" class="config-item__banner" v-if="!dashboard.backgroundImage.length">
|
||
<img src="https://cdn.cunwuyun.cn/dvcp/dv/tpl/upload.png">
|
||
<span>点击上传/修改</span>
|
||
</div>
|
||
</ai-uploader>
|
||
</div>
|
||
</div>
|
||
<div class="layout-config__item">
|
||
<label>重置</label>
|
||
<div class="layout-config__item--right layout-config__item--btn">
|
||
<div @click="dashboard.backgroundImage = []">恢复默认背景</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div
|
||
class="layout-menu"
|
||
v-if="activeIndex > -1 && isShowMenu"
|
||
:style="{top: menuY + 'px', left: menuX + 'px'}">
|
||
<div class="layout-menu__item" @click="removeLayer">
|
||
<span>删除图层</span>
|
||
</div>
|
||
<div class="layout-menu__item" @click="copyLayer">
|
||
<span>复制图层</span>
|
||
</div>
|
||
<div class="layout-menu__item" @click="setTop">
|
||
<span>置顶图层</span>
|
||
</div>
|
||
<div class="layout-menu__item" @click="setBottom">
|
||
<span>置底图层</span>
|
||
</div>
|
||
</div>
|
||
<ai-dialog :visible.sync="isShowImg" append-to-body title="图片素材" @onConfirm="isShowImg = false">
|
||
<el-button type="primary" style="margin-bottom: 20px" @click="isShowAddImg = true">添加图片</el-button>
|
||
<ai-table
|
||
:tableData="images"
|
||
:total="images.length"
|
||
:colConfigs="colConfigs"
|
||
@getList="() => {}">
|
||
<el-table-column slot="img" label="图片" align="center">
|
||
<template slot-scope="{ row }">
|
||
<ai-uploader
|
||
:instance="instance"
|
||
:value="[{url: row.url}]"
|
||
disabled
|
||
:limit="1">
|
||
</ai-uploader>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column slot="options" width="140px" fixed="right" label="操作" align="center">
|
||
<template slot-scope="{ row, $index }">
|
||
<div class="table-options">
|
||
<el-button type="text" @click="removeImg($index)">删除</el-button>
|
||
<el-button type="text" @click="copy(row.url)">复制链接</el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</ai-table>
|
||
</ai-dialog>
|
||
<ai-dialog :visible.sync="isShowAddImg" width="580px" append-to-body title="添加图片" @closed="form.images = []" @onConfirm="onImageConfirm">
|
||
<ai-uploader
|
||
:instance="instance"
|
||
v-model="form.images"
|
||
:limit="9">
|
||
<template slot="tips">
|
||
<p>最多上传9张图片,单个文件最大10MB,支持jpg、jpeg、png格式</p>
|
||
</template>
|
||
</ai-uploader>
|
||
</ai-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { components } from '../config'
|
||
import VueRulerTool from 'vue-ruler-tool'
|
||
import VueDraggableResizable from 'vue-draggable-resizable'
|
||
import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
|
||
import DataConfig from './form/DataConfig.vue'
|
||
import RenderElement from './RenderElement'
|
||
|
||
export default {
|
||
props: {
|
||
instance: Function,
|
||
dict: Object,
|
||
params: Object,
|
||
urlPrefix: String
|
||
},
|
||
|
||
data() {
|
||
return {
|
||
colConfigs: [
|
||
// { prop: 'url', label: '图片链接', showOverflowTooltip: false },
|
||
{ slot: 'img', label: '图片' }
|
||
],
|
||
form: {
|
||
images: []
|
||
},
|
||
isShowAddImg: false,
|
||
isShowImg: false,
|
||
parentIndex: 0,
|
||
subIndex: 0,
|
||
sonIndex: 0,
|
||
leftIndex: 0,
|
||
rightIndex: 1,
|
||
configIndex: 0,
|
||
components,
|
||
bigscreenWidth: 1920,
|
||
bigscreenHeight: 1080,
|
||
widthPaddingTools: 18,
|
||
componentList: [],
|
||
dashboard: {
|
||
title: '大屏',
|
||
width: 1920,
|
||
height: 1080,
|
||
backgroundColor: '',
|
||
backgroundImage: []
|
||
},
|
||
menuX: 0,
|
||
menuY: 0,
|
||
isShowMenu: false,
|
||
activeIndex: -1,
|
||
middleWidth: 0,
|
||
middleHeight: 0,
|
||
widthScale: 0,
|
||
heightScale: 0,
|
||
bigscreenScaleInWorkbench: 0,
|
||
tableStatus: [{
|
||
label: '是',
|
||
value: '1'
|
||
}, {
|
||
label: '否',
|
||
value: '0'
|
||
}],
|
||
images: [],
|
||
summaryList: ['summary0', 'summary1', 'summary2', 'summary3', 'summary4', 'summary5', 'summary7', 'summary9', 'summary10'],
|
||
borderList: ['border0', 'border1', 'border2', 'border3', 'border4']
|
||
}
|
||
},
|
||
|
||
components: {
|
||
RenderElement,
|
||
DataConfig,
|
||
VueRulerTool,
|
||
VueDraggableResizable,
|
||
},
|
||
|
||
computed: {
|
||
workbenchTransform() {
|
||
return `scale(${this.heightScale})`
|
||
},
|
||
|
||
currLayout() {
|
||
if (this.activeIndex === -1) return {}
|
||
|
||
return this.componentList[this.activeIndex]
|
||
},
|
||
|
||
widget() {
|
||
if (this.components.length && this.components[this.parentIndex].list.length) {
|
||
return this.components[this.parentIndex].list[this.subIndex].list
|
||
}
|
||
|
||
return []
|
||
}
|
||
},
|
||
|
||
mounted() {
|
||
if (this.params && this.params.id) {
|
||
this.getInfo(this.params.id)
|
||
}
|
||
this.$nextTick(() => {
|
||
this.middleWidth = document.querySelector('.layout-wrapper').offsetWidth - 670
|
||
this.middleHeight = document.querySelector('.layout-wrapper').offsetHeight
|
||
this.initCanvas()
|
||
})
|
||
},
|
||
|
||
methods: {
|
||
bindEvent() {
|
||
this.middleWidth = document.querySelector('.layout-wrapper').offsetWidth - 670
|
||
this.middleHeight = document.querySelector('.layout-wrapper').offsetHeight
|
||
|
||
this.$nextTick(() => {
|
||
this.initCanvas()
|
||
})
|
||
},
|
||
|
||
copy (link) {
|
||
let oInput = document.createElement('input')
|
||
oInput.value = link
|
||
document.body.appendChild(oInput)
|
||
oInput.select()
|
||
document.execCommand('Copy')
|
||
this.$message({
|
||
message: '已复制',
|
||
type: 'success'
|
||
})
|
||
oInput.remove()
|
||
},
|
||
|
||
removeImg (index) {
|
||
this.images.splice(index, 1)
|
||
},
|
||
|
||
onImageConfirm () {
|
||
if (!this.form.images.length) {
|
||
return this.$message.error('请上传图片')
|
||
}
|
||
|
||
this.images = [
|
||
...this.images,
|
||
...this.form.images
|
||
]
|
||
|
||
this.form.images = []
|
||
this.isShowAddImg = false
|
||
},
|
||
|
||
setTop() {
|
||
const maxZindex = Math.max.apply(Math, this.componentList.map(item => {
|
||
return item.zIndex
|
||
}))
|
||
|
||
this.$set(this.componentList[this.activeIndex], 'zIndex', maxZindex + 1)
|
||
},
|
||
|
||
setBottom() {
|
||
const item = this.componentList[this.activeIndex]
|
||
this.componentList.splice(this.activeIndex, 1)
|
||
this.componentList.unshift(item)
|
||
},
|
||
|
||
getInfo(id) {
|
||
this.instance.post(`${this.urlPrefix}/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
|
||
if (res.code === 0) {
|
||
const data = JSON.parse(res.data.config)
|
||
this.componentList = data.config
|
||
this.dashboard = data.dashboard
|
||
this.images = data.images || []
|
||
}
|
||
})
|
||
},
|
||
|
||
back() {
|
||
this.$emit('close')
|
||
},
|
||
|
||
save() {
|
||
this.instance.post(`${this.urlPrefix}/appdiylargescreen/addOrUpdateLargeScreen`, {
|
||
config: JSON.stringify({
|
||
config: this.componentList,
|
||
dashboard: this.dashboard,
|
||
images: this.images
|
||
}),
|
||
status: 1,
|
||
title: this.dashboard.title,
|
||
id: this.params.id || ''
|
||
}).then(res => {
|
||
if (res.code == 0) {
|
||
this.$message.success('保存成功')
|
||
this.$emit('change', res.data)
|
||
this.back()
|
||
}
|
||
})
|
||
},
|
||
|
||
clone(e) {
|
||
this.componentList.push(this.deepClone(e))
|
||
},
|
||
|
||
onChange(e) {
|
||
if (e.indexOf('Chart') > -1) {
|
||
this.$refs[`chart${this.activeIndex}`][0].refresh()
|
||
}
|
||
},
|
||
|
||
deepClone(data, hash = new WeakMap()) {
|
||
if (typeof data !== 'object' || data === null) {
|
||
throw new TypeError('传入参数不是对象')
|
||
}
|
||
if (hash.has(data)) {
|
||
return hash.get(data)
|
||
}
|
||
let newData = {}
|
||
const dataKeys = Object.keys(data)
|
||
dataKeys.forEach(value => {
|
||
const currentDataValue = data[value]
|
||
if (typeof currentDataValue !== "object" || currentDataValue === null) {
|
||
newData[value] = currentDataValue
|
||
} else if (Array.isArray(currentDataValue)) {
|
||
newData[value] = [...currentDataValue]
|
||
} else if (currentDataValue instanceof Set) {
|
||
newData[value] = new Set([...currentDataValue])
|
||
} else if (currentDataValue instanceof Map) {
|
||
newData[value] = new Map([...currentDataValue])
|
||
} else {
|
||
hash.set(data, data)
|
||
newData[value] = this.deepClone(currentDataValue, hash)
|
||
}
|
||
})
|
||
return newData
|
||
},
|
||
|
||
onContextmenu(e, index) {
|
||
this.menuX = e.clientX + 10
|
||
this.menuY = e.clientY + 10
|
||
this.activeIndex = index
|
||
this.isShowMenu = true
|
||
|
||
e.preventDefault()
|
||
},
|
||
|
||
copyLayer() {
|
||
const layer = this.deepClone(this.componentList[this.activeIndex])
|
||
this.componentList.push(layer)
|
||
},
|
||
|
||
removeLayer() {
|
||
this.componentList.splice(this.activeIndex, 1)
|
||
this.activeIndex = -1
|
||
},
|
||
|
||
onActivated(index) {
|
||
this.activeIndex = index
|
||
},
|
||
|
||
|
||
onDrag(x, y, index) {
|
||
this.$set(this.componentList[index], 'left', x)
|
||
this.$set(this.componentList[index], 'top', y)
|
||
},
|
||
|
||
onResizing(x, y, w, h, index, type) {
|
||
this.$set(this.componentList[index], 'left', x)
|
||
this.$set(this.componentList[index], 'top', y)
|
||
this.$set(this.componentList[index], 'width', w)
|
||
this.$set(this.componentList[index], 'height', h)
|
||
|
||
if (type.indexOf('Chart') > -1) {
|
||
this.$refs[`chart${index}`][0].watchResize()
|
||
}
|
||
},
|
||
|
||
initCanvas() {
|
||
var widthScale = (this.middleWidth - this.widthPaddingTools) / this.bigscreenWidth
|
||
var heightScale = (this.middleHeight - this.widthPaddingTools) / this.bigscreenHeight
|
||
this.heightScale = Math.min(widthScale, heightScale)
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.layout {
|
||
position: fixed;
|
||
left: 0;
|
||
top: 0;
|
||
z-index: 111;
|
||
width: 100%;
|
||
height: 100%;
|
||
color: #fff;
|
||
background: #1d1e1f;
|
||
|
||
::v-deep .dv-scroll-board {
|
||
height: calc(100%) !important;
|
||
|
||
.header-item {
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-size: 16px;
|
||
}
|
||
|
||
.index {
|
||
display: inline-block;
|
||
width: 26px;
|
||
height: 26px;
|
||
line-height: 26px;
|
||
font-size: 16px;
|
||
background-color: #4F57FF !important;
|
||
}
|
||
}
|
||
|
||
.layout-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
height: 50px;
|
||
background: #1D1E1F;
|
||
|
||
h2 {
|
||
font-size: 16px;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.layout-header__right {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
height: 40px;
|
||
padding: 0 20px;
|
||
|
||
span {
|
||
width: 60px;
|
||
height: 50px;
|
||
line-height: 50px;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
color: #fff;
|
||
transition: all 0.3s ease;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
background: #191d22;
|
||
|
||
&:hover {
|
||
opacity: 0.8;
|
||
background: #191d22;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.layout-wrapper {
|
||
display: flex;
|
||
height: calc(100% - 50px);
|
||
}
|
||
|
||
.layout-page__setting {
|
||
& > h2 {
|
||
height: 40px;
|
||
line-height: 40px;
|
||
padding: 0 10px;
|
||
font-size: 14px;
|
||
background: #232B35;
|
||
}
|
||
|
||
.layout-config__item--bg {
|
||
width: 232px;
|
||
height: 120px;
|
||
background: #262C33;
|
||
border: 1px solid #030411;
|
||
overflow: hidden;
|
||
user-select: none;
|
||
|
||
&:hover {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
::v-deep .el-upload-list--picture-card, ::v-deep.el-upload-list__item-thumbnail, ::v-deep .uploader {
|
||
width: 232px;
|
||
height: 120px;
|
||
}
|
||
|
||
::v-deep .el-upload-list--picture-card .el-upload-list__item {
|
||
width: 232px;
|
||
height: 120px;
|
||
}
|
||
|
||
::v-deep .el-upload--picture-card {
|
||
background-color: transparent;
|
||
}
|
||
|
||
.config-item__banner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
width: 232px;
|
||
height: 120px;
|
||
line-height: 1;
|
||
|
||
span {
|
||
margin-top: 4px;
|
||
color: #CBDBE7;
|
||
font-size: 12px;
|
||
}
|
||
|
||
img {
|
||
width: 32px;
|
||
height: 32px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
::v-deep #dv-full-screen-container {
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
}
|
||
|
||
::-webkit-scrollbar {
|
||
width: 5px;
|
||
height: 14px;
|
||
}
|
||
|
||
::-webkit-scrollbar-corner {
|
||
background: transparent;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
min-height: 20px;
|
||
background-clip: content-box;
|
||
box-shadow: 0 0 0 5px rgba(116, 148, 170, 0.5) inset;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
box-shadow: 1px 1px 5px rgba(116, 148, 170, 0.5) inset;
|
||
}
|
||
|
||
.coordinate {
|
||
div {
|
||
position: absolute;
|
||
|
||
&.coordinate-label {
|
||
left: -10px;
|
||
top: -10px;
|
||
font-size: 20px;
|
||
color: #09f;
|
||
transform: translate(-100%, -100%);
|
||
}
|
||
|
||
&.coordinate-left {
|
||
left: 0;
|
||
width: 100000px;
|
||
height: 0;
|
||
border: 1px dashed #09f;
|
||
transform: translateX(-100%);
|
||
}
|
||
|
||
&.coordinate-top {
|
||
left: 0;
|
||
height: 100000px;
|
||
width: 0;
|
||
border: 1px dashed #09f;
|
||
transform: translateY(-100%);
|
||
}
|
||
}
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.layout-tab {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 50px;
|
||
|
||
span {
|
||
flex: 1;
|
||
height: 100%;
|
||
line-height: 50px;
|
||
text-align: center;
|
||
color: #fff;
|
||
font-size: 15px;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
background: #14161A;
|
||
border-top: 2px solid transparent;
|
||
transition: all 0.3s ease;
|
||
|
||
&.layout-tab__active {
|
||
background: #1D2127;
|
||
color: #2266FF;
|
||
border-top: 2px solid #3383FF;
|
||
}
|
||
}
|
||
}
|
||
|
||
.layout-menu {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 1100;
|
||
width: 150px;
|
||
user-select: none;
|
||
|
||
.layout-menu__item {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 32px;
|
||
line-height: 32px;
|
||
padding: 0 20px;
|
||
color: #bcc9d4;
|
||
font-size: 14px;
|
||
background: #2b323b;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
border-left: 2px solid transparent;
|
||
|
||
&:hover {
|
||
background: #1d262e;
|
||
color: #2681ff;
|
||
border-left: 2px solid #2681ff;
|
||
}
|
||
}
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.layout-left {
|
||
width: 330px;
|
||
height: 100%;
|
||
flex-shrink: 0;
|
||
background: #1D2127;
|
||
|
||
& > h2 {
|
||
height: 40px;
|
||
line-height: 40px;
|
||
padding: 0 10px;
|
||
background: #232B35;
|
||
font-size: 14px;
|
||
color: #fff;
|
||
box-shadow: -1px 0px 0px 0px #000000;
|
||
}
|
||
|
||
.layout-left__middle {
|
||
width: 80px;
|
||
height: 100%;
|
||
background: #11151A;
|
||
overflow-y: auto;
|
||
|
||
& > div {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 50px;
|
||
user-select: none;
|
||
transition: all 0.3s ease;
|
||
|
||
&.layout-left__middle--item {
|
||
cursor: pointer;
|
||
}
|
||
|
||
&.active, &.layout-left__middle--item:hover {
|
||
color: #3383FF;
|
||
background: #0A0B0D;
|
||
}
|
||
}
|
||
}
|
||
|
||
.layout-left__right {
|
||
flex: 1;
|
||
padding: 0 10px;
|
||
background: #0A0B0D;
|
||
|
||
.layout-left__right--item {
|
||
margin-top: 10px;
|
||
background: #212326;
|
||
|
||
&:hover {
|
||
opacity: 0.8;
|
||
cursor: pointer;
|
||
}
|
||
|
||
img {
|
||
width: 180px;
|
||
height: 80px;
|
||
}
|
||
|
||
span {
|
||
display: block;
|
||
height: 24px;
|
||
line-height: 24px;
|
||
padding: 0 10px;
|
||
font-size: 12px;
|
||
background: #212326;
|
||
}
|
||
}
|
||
}
|
||
|
||
.layout-left__wrapper {
|
||
display: flex;
|
||
height: calc(100% - 40px);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.layout-left__left {
|
||
width: 50px;
|
||
background: #1D2126;
|
||
|
||
div {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
height: 64px;
|
||
font-size: 12px;
|
||
color: #fff;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
user-select: none;
|
||
border-left: 2px solid transparent;
|
||
|
||
&.active, &:hover {
|
||
color: #3383FF;
|
||
border-left: 2px solid #3383FF;
|
||
background: #11151A;
|
||
}
|
||
|
||
span {
|
||
margin-top: 6px;
|
||
font-size: 12px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.components-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 48px;
|
||
color: #bfcbd9;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
|
||
.tools-item-icon {
|
||
color: #409eff;
|
||
margin-right: 10px;
|
||
width: 53px;
|
||
height: 30px;
|
||
line-height: 30px;
|
||
text-align: center;
|
||
display: block;
|
||
border: 1px solid #3a4659;
|
||
background: #282a30;
|
||
}
|
||
}
|
||
}
|
||
|
||
.layout-middle {
|
||
flex: 1;
|
||
|
||
.canvas-wrapper {
|
||
position: relative;
|
||
-webkit-transform-origin: 0 0;
|
||
transform-origin: 0 0;
|
||
-webkit-box-sizing: border-box;
|
||
box-sizing: border-box;
|
||
height: 100%;
|
||
margin: 0;
|
||
padding: 0;
|
||
|
||
.vueRuler {
|
||
width: 100%;
|
||
padding: 18px 0 0 18px;
|
||
|
||
::v-deep .vue-ruler-ref-line-v, ::v-deep .vue-ruler-ref-line-h {
|
||
display: none;
|
||
}
|
||
|
||
::v-deep .vue-ruler-v {
|
||
.n {
|
||
transform: rotate(180deg);
|
||
}
|
||
}
|
||
}
|
||
|
||
.workbench {
|
||
background-color: #1e1e1e;
|
||
position: relative;
|
||
-webkit-user-select: none;
|
||
-moz-user-select: none;
|
||
-ms-user-select: none;
|
||
user-select: none;
|
||
-webkit-transform-origin: 0 0;
|
||
transform-origin: 0 0;
|
||
margin: 0;
|
||
}
|
||
}
|
||
|
||
::v-deep .handle {
|
||
border-radius: 100%;
|
||
border: none;
|
||
background-color: #09f;
|
||
width: 14px;
|
||
height: 14px;
|
||
|
||
&.handle-tl, &.handle-tm {
|
||
transform: translate(2px, 2px);
|
||
}
|
||
}
|
||
|
||
.draggable {
|
||
position: absolute;
|
||
border: none;
|
||
|
||
&::after {
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
z-index: 1;
|
||
width: 100%;
|
||
height: 100%;
|
||
cursor: move;
|
||
content: ' ';
|
||
}
|
||
|
||
&:hover {
|
||
cursor: move;
|
||
border: 1px dashed #09f;
|
||
background-color: rgba(115, 170, 229, 0.3);
|
||
}
|
||
}
|
||
|
||
.drag-active {
|
||
cursor: move;
|
||
border: 1px dashed #09f;
|
||
background-color: rgba(115, 170, 229, .3);
|
||
}
|
||
}
|
||
|
||
.layout-right {
|
||
width: 340px;
|
||
height: 100%;
|
||
flex-shrink: 0;
|
||
border-left: 1px solid #000000;
|
||
background: #1D2127;
|
||
|
||
::v-deep .el-input-number {
|
||
width: 106px;
|
||
margin-right: 20px;
|
||
|
||
&:last-child {
|
||
margin-right: 0;
|
||
}
|
||
|
||
.el-input-number__decrease, .el-input-number__increase {
|
||
background: #262C33;
|
||
color: #fff;
|
||
border-color: #030411;
|
||
}
|
||
|
||
input {
|
||
background: #262C33;
|
||
font-size: 12px;
|
||
color: #fff;
|
||
border: 1px solid #030411;
|
||
}
|
||
}
|
||
|
||
.layout-right__content {
|
||
height: calc(100% - 40px);
|
||
overflow-y: overlay;
|
||
overflow-x: hidden;
|
||
|
||
.layout-config__group {
|
||
padding: 10px 10px 20px;
|
||
border-bottom: 1px solid #000000;
|
||
|
||
& > h2 {
|
||
margin-bottom: 20px;
|
||
color: #FFFFFF;
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
|
||
.layout-config__item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 10px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
::v-deep .el-select, ::v-deep .el-cascader {
|
||
color: #fff;
|
||
background: transparent;
|
||
|
||
input {
|
||
width: 232px;
|
||
background: #262C33;
|
||
font-size: 12px;
|
||
color: #fff;
|
||
border: 1px solid #030411;
|
||
}
|
||
}
|
||
|
||
label {
|
||
flex-shrink: 0;
|
||
width: 60px;
|
||
color: #FFFFFF;
|
||
font-size: 12px;
|
||
text-align: right;
|
||
}
|
||
|
||
.layout-config__item--btn {
|
||
flex: 1;
|
||
margin-left: 28px;
|
||
|
||
div {
|
||
width: 106px;
|
||
height: 24px;
|
||
line-height: 24px;
|
||
text-align: center;
|
||
font-size: 12px;
|
||
color: #3383FF;
|
||
background: #1D2127;
|
||
border: 1px solid #3383FF;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
|
||
&:hover {
|
||
opacity: 0.8;
|
||
}
|
||
}
|
||
}
|
||
|
||
&.layout-config__item--input ::v-deep input {
|
||
width: 232px;
|
||
background: #262C33;
|
||
font-size: 12px;
|
||
color: #fff;
|
||
border: 1px solid #030411;
|
||
}
|
||
|
||
.layout-config__item--right {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|