Files
dvcp_v2_webapp/packages/bigscreen/designer/viewport.vue
2024-08-14 09:02:53 +08:00

1120 lines
29 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="preview">预览</span>
<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" :class="{hide:leftHide}">
<h2 class="flex">
<div class="fill">全部资产</div>
<el-button class="leftHideBtn" type="text" @click="leftHide=!leftHide">{{
leftHide ? "展开" : "收起"
}}
</el-button>
</h2>
<div class="layout-left__wrapper">
<div class="layout-left__left">
<div @click="subIndex = 0, parentIndex = index" :class="{active: parentIndex === index}"
v-for="(item, index) in components" :key="index">
<i class="iconfont iconqiyeguanli"></i>
<span>{{ item.label }}</span>
</div>
</div>
<div class="layout-left__middle" v-if="hasCategories">
<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" v-if="resizeWrapper"
class="vueRuler"
:step-length="50"
parent
is-scale-revise
position="relative"
:visible.sync="dashboard.presetLineVisible">
<div id="workbench"
class="workbench"
:style="{
transform: workbenchTransform,
width: bigscreenWidth + 'px',
height: bigscreenHeight + 'px'
}">
<ai-dv-wrapper
style="height: 100%"
:type="dashboard.style"
:title="$route.query.name"
:titleSize="dashboard.titleSize"
:theme="dashboard.theme"
:background="dashboard.theme == 1 ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj_bg.png' : (dashboard.backgroundImage.length ? dashboard.backgroundImage[0].url : '')">
<div style="width: 100%; height: 100%">
<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)"
@dragstop="(x, y) => onDrag(x, y,item)"
@resizestop="(x, y, w, h) => onResizing(x, y, w, h, item)"
@activated="onActivated(index)"
@click.native.stop
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>
<ai-dv-render :data="item" :theme="dashboard.theme" :index="index" :instance="instance"/>
</vue-draggable-resizable>
</div>
</ai-dv-wrapper>
</div>
</vue-ruler-tool>
</div>
</div>
<div class="layout-right" @click.stop>
<!-- 选中组件面板-->
<template v-if="activeIndex > -1">
<div class="layout-tab">
<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">
<component-config v-show="configIndex === 0" :config="currLayout" v-bind="$props"/>
<div class="layout-right__content--wrapper" v-show="configIndex === 1"
v-if="currLayout.type !== 'title' && currLayout.type !== 'video'">
<data-config v-model="currLayout" :instance="instance" :dict="dict" @change="onChange('barChart')"/>
</div>
</div>
</template>
<!--未选中组件,页面设置-->
<div class="layout-page__setting layout-right__content" v-else>
<h2>页面设置</h2>
<div class="layout-config__group">
<config-item label="屏幕大小">
<el-input-number size="mini" :min="0" v-model="bigscreenWidth" controls-position="right"/>
<el-input-number size="mini" :min="0" v-model="bigscreenHeight" controls-position="right"/>
</config-item>
<config-item label="屏幕标题">
<el-input v-model="dashboard.title" size="mini"/>
<el-input type="number" v-model="dashboard.titleSize" size="mini" placeholder="字体大小" :max="68"/>
</config-item>
<config-item label="主题设置">
<el-select size="mini" v-model="dashboard.theme" placeholder="请选择">
<el-option label="默认" value="0"></el-option>
<el-option label="党建" value="1"></el-option>
</el-select>
</config-item>
<config-item label="样式设置">
<el-select size="mini" v-model="dashboard.style" placeholder="请选择">
<el-option label="默认" value="black"/>
<el-option label="经典" value="classic"/>
</el-select>
</config-item>
<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'" prop="素材地址" label="素材" align="center">
</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"
fileType="file"
:maxSize="100"
url="/admin/file/add-unlimited"
:limit="9">
</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 './components/DataConfig.vue'
import ComponentConfig from "./components/componentConfig.vue";
import {mapActions} from "vuex"
import Vue from "vue";
import ConfigItem from "./components/configItem.vue";
export default {
name: "viewport",
provide() {
return {
setCurLayer: this.setCurLayer
}
},
props: {
instance: Function,
dict: Object,
},
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: '大屏',
titleSize: 38,
width: 1920,
height: 1080,
theme: '0',
backgroundColor: '',
backgroundImage: [],
style: 'black'
},
menuX: 0,
menuY: 0,
isShowMenu: false,
activeIndex: -1,
middleWidth: 0,
middleHeight: 0,
widthScale: 0,
heightScale: 0,
images: [],
leftHide: false,
resizeWrapper: true
}
},
components: {
ConfigItem,
ComponentConfig,
DataConfig,
VueRulerTool,
VueDraggableResizable,
},
computed: {
workbenchTransform() {
return `scale(${this.heightScale})`
},
currLayout: {
set(v) {
this.setCurLayer(v)
},
get() {
return this.activeIndex > -1 ? this.componentList[this.activeIndex] : {}
}
},
widget() {
const categories = this.components[this.parentIndex].list
if (categories.length) {
return categories[this.subIndex]?.list || categories
}
return []
},
hasCategories: v => v.components[v.parentIndex].list[v.subIndex].list?.length > 0,
comps: v => {
const obj = {}
const handleOps = e => {
e.echartOps = e.echartOps || v.$echartTpls[e.type]
obj[e.type] = e
}
v.components.map(e => e.list.map(c => c.list?.map(handleOps) || handleOps(c)))
return obj
}
},
mounted() {
this.dict.load("yesOrNo")
this.getInfo(this.$route.query.did)
this.$nextTick(() => {
this.middleWidth = document.querySelector('.layout-wrapper').offsetWidth - 670
this.middleHeight = document.querySelector('.layout-wrapper').offsetHeight
this.initCanvas()
})
},
watch: {
leftHide: {
handler(v) {
this.middleWidth = document.querySelector('.layout-wrapper').offsetWidth - (v ? 340 : 670)
this.initCanvas()
this.resizeWrapper = false
this.$nextTick(() => this.resizeWrapper = true)
}
}
},
methods: {
...mapActions(['closePage']),
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) {
id && this.instance.post(`/app/appdiylargescreen/queryLargeScreenDetailById?id=${id}`).then(res => {
if (res?.data) {
const data = JSON.parse(res.data.config)
const getComp = type => this.comps[type] || {}
this.componentList = data.config.filter(Boolean).map(e => ({...getComp(e.type), ...e}))
this.dashboard = data.dashboard
this.images = data.images || []
}
})
},
back() {
const {id} = this.$route.query
this.$router.push({hash: "#add", query: {id}})
this.closePage()
},
save() {
const {did: id, id: pid} = this.$route.query, {dashboard} = this
this.instance.post(`/app/appdiylargescreen/addOrUpdateLargeScreen`, {
id, pid,
config: JSON.stringify({
config: this.componentList,
dashboard,
images: this.images
}),
status: 1,
title: dashboard.title,
}).then(res => {
if (res?.code == 0) {
this.$message.success('保存成功')
this.getInfo(this.$route.query.did)
}
})
},
//从资产中新建时使用
clone(e) {
if (/Chart/.test(e.type)) {
e.echartOps = this.$echartTpls[e.config]
}
this.componentList.push(this.deepClone(e))
},
onChange() {
this.$refs[`chart${this.activeIndex}`]?.[0]?.refresh()
},
deepClone(obj) {
if (obj instanceof Object) {
let newObj = {}
if (Array.isArray(obj)) {
return this.$copy(obj)
} else if (typeof obj == 'function') {
newObj = obj.bind(newObj)
} else {
for (let key in obj) {
let value = obj[key]
if (typeof value == 'function') {
newObj[key] = value.bind(newObj)
} else if (typeof value == 'object') {
if (Array.isArray(value)) {
newObj[key] = []
value.forEach(item => {
newObj[key].push(this.deepClone(item))
})
} else {
newObj[key] = this.deepClone(value)
}
} else {
newObj[key] = value
}
}
}
return newObj
} else {
return obj
}
},
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, item) {
item.left = x
item.top = y
},
onResizing(x, y, w, h, item) {
item.left = x
item.top = y
item.width = w
item.height = h
},
initCanvas() {
let widthScale = (this.middleWidth - this.widthPaddingTools) / this.bigscreenWidth
let heightScale = (this.middleHeight - this.widthPaddingTools) / this.bigscreenHeight
this.heightScale = Math.min(widthScale, heightScale)
},
preview() {
const {origin, pathname} = location
window.open(origin + pathname + '?id=' + this.$route.query.did + "#preview")
},
setCurLayer(v) {
this.componentList.splice(this.activeIndex, 1, v)
}
},
created() {
Vue.use(window.AVUE, {
size: 'mini',
tableSize: 'mini',
calcHeight: 36,
})
}
}
</script>
<style lang="scss" scoped>
.layout {
position: fixed;
left: 0;
top: 0;
z-index: 111;
width: 100%;
height: 100%;
color: #fff;
background: #1d1e1f;
: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;
}
:deep( .el-upload-list--picture-card), :deep(.el-upload-list__item-thumbnail), :deep( .uploader ) {
width: 232px;
height: 120px;
}
:deep( .el-upload-list--picture-card .el-upload-list__item ) {
width: 232px;
height: 120px;
}
: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;
}
}
}
}
: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;
&.hide {
width: 0;
position: relative;
h2 > .fill {
display: none;
}
.leftHideBtn {
position: absolute;
left: 0;
top: 0;
transform: translate(0, -100%);
}
}
& > 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;
overflow-y: auto;
overflow-x: hidden;
.layout-left__right--item {
margin-top: 10px;
background: #212326;
&:hover {
opacity: 0.8;
cursor: pointer;
}
img {
width: auto;
height: auto;
max-height: 130px;
max-width: 100%;
margin-left: 50%;
transform: translateX(-50%);
}
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;
min-width: 0;
background: #000;
.canvas-wrapper {
position: relative;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
box-sizing: border-box;
height: 100%;
margin: 0;
padding: 0;
.vueRuler {
width: 100%;
padding: 18px 0 0 18px;
:deep( .vue-ruler-ref-line-v), :deep( .vue-ruler-ref-line-h ) {
display: none;
}
: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;
}
}
: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;
transition: 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;
: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;
}
}
:deep(.layout-right__content ) {
height: calc(100% - 50px);
overflow-y: auto;
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;
}
.el-select, .el-cascader {
width: 232px;
color: #fff;
background: transparent;
input {
width: 100%;
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 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>