<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，支持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.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>
