Files
dvcp_v2_webapp/packages/bigscreen/designer/components/Layout.vue
2021-12-28 16:34:27 +08:00

1181 lines
33 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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-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支持jpgjpegpng格式</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.push(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>