<template>
  <div class="content" >
    <div class="leftTree fleft">
      <div class="head">
        <div class="title">设备分组</div>
        <div class="nodeEdit" @click="addNode(null)">新增</div>
      </div>
      <div class="Search">
        <input type="text" class="txt" v-model="searchTxt" placeholder="输入分组名称" />

      </div>

      <div class="treeContent">
        <el-tree :data="treeData" :props="defaultProps" accordion @node-click="handleNodeClick" :highlight-current="true">
          <template #default="{ node, data }">

            <div class="custom-tree-node" >
              <span :class="data.parentId != null ? '' : 'treeBold'">{{ node.label }}</span>

              <div class="iconContent">

                <Edit class="icon" @click.stop="editNode(node)" />
                <Plus class="icon" @click.stop="addNode(node)" />
                <Delete class="icon red" @click.stop="delNode(node)" />

              </div>
            </div>

          </template>
        </el-tree>
      </div>


    </div>


    <div class="main fleft">
      <div class="toolBar">
        <div class="btnAdd" @click="showDevice">
          <Plus class="icon" style="width: 14px;height: 14px;" />
          添加设备
        </div>
        <div class="rightSearch">
          <div class="searchContent">
            <div class="center H100">
              <input type="text" class="serchTxt" v-model="GjSearchForm.deviceName" @input="InputSearch()" />
              <Search class="icon" style="width: 16px;height:16px;" />
            </div>
          </div>

          <div class="gjSearch" @click="ToggleGjSearch()">高级筛选</div>
        </div>
      </div>

      <div class="searchBar" :class="Status.isGjSearch ? '' : 'displayNone'">
        <div style="margin-top:20px;">
          <el-form class="demo-form-inline" :inline="true" :model="GjSearchForm" label-width="auto"
            style="width: 100%;">

            <el-form-item label="设备类型">
              <el-select v-model="GjSearchForm.deviceType" placeholder="请选择">
                <el-option v-for="item in deviceTypes" :key="item.value" :label="item.typeName" :value="item.value" />
              </el-select>
            </el-form-item>

            <el-form-item label="通信方式">
              <el-select v-model="GjSearchForm.netMode" placeholder="请选择">
                <el-option label="4G" :value="0" />
                <el-option label="蓝牙" :value="1" />
              </el-select>
            </el-form-item>
            <el-form-item>

              <div class="btnSearch" @click="getDeviceList()">查询</div>
              <div class="btnReset" @click="ResetQuery()">重置</div>
            </el-form-item>

          </el-form>
        </div>

      </div>

      <div class="grid">
        <el-card shadow="hover">
          <div class="gridTool">




            <div class="button-row">

              <el-button type="success" @click="showCheckGroup('check')" plain>移动</el-button>

              <el-button type="danger" plain @click="groupDelDevice()">删除</el-button>
            </div>

          </div>
          <el-table ref="grid" height="calc(100vh - 320px)" v-loading="Status.loading" border :data="deviceList"
            @selection-change="RowSelectionChange">
            <el-table-column type="selection" width="50" align="center" />
            <el-table-column label="设备名称" align="center" prop="deviceName" />

            <el-table-column prop="devicePic" label="设备图片">
              <template #default="scope">
                <el-popover placement="right" trigger="click">
                  <template #reference>
                    <img :src="scope.row.devicePic"
                      style="width: 40px; height: 40px; cursor: pointer; object-fit: contain"
                      class="hover:opacity-80 transition-opacity" />
                  </template>
                  <img :src="scope.row.devicePic" style="max-width: 600px; max-height: 600px; object-fit: contain" />
                </el-popover>
              </template>
            </el-table-column>

            <el-table-column prop="typeName" label="设备类型" />
            <el-table-column prop="bindingStatus" label="绑定状态">
              <template #default="scope">
                <el-tag :type="scope.row.bindingStatus === 1 ? 'success' : 'info'">
                  {{ scope.row.bindingStatus === 1 ? '已绑定' : '未绑定' }}
                </el-tag>
              </template>
            </el-table-column>


            <el-table-column label="操作" fixed="right" width="280" class-name="small-padding fixed-width">
              <template #default="scope">
                <div class="center">
                  <div class="moveDev" @click="showCheckGroup('item', scope.row)">移动</div>
                  <div class="delDev" @click="groupDelDevice(scope.row)">删除</div>
                </div>

              </template>
            </el-table-column>
          </el-table>
          <pagination v-show="pagin.total > 0" v-model:page="GjSearchForm.pageNum" v-model:limit="GjSearchForm.pageSize"
            :total="pagin.total" @pagination="getDeviceList" />
        </el-card>

      </div>
    </div>

    <div class="clear"></div>


    <!-- 提示框 -->
    <el-dialog :width="300" :draggable="true" v-model="Status.confirm.Visible" :title="Status.confirm.title" width="500" center>
      <span>
        {{ Status.confirm.text }}
      </span>
      <template #footer>
        <div class="dialog-footer">
          <el-button v-show="Status.confirm.showCancel" @click="Status.confirm.cancelCallback">取消</el-button>
          <el-button type="primary" @click="Status.confirm.OkCallback">
            确定
          </el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 选择分组的弹窗 -->
    <el-dialog v-model="Status.dialogGroupVisible" title="选择分组" width="500" :draggable="true">

      <el-tree :data="treeData" :props="defaultProps" accordion>
        <template #default="{ node, data }">

          <div class="custom-tree-node" @click.stop="CheckGroup(data)">
            <span :class="data.parentId != null ? '' : 'treeBold'">{{ node.label }}</span>
            <span>选择</span>
          </div>

        </template>
      </el-tree>
      <el-button type="primary" @click="OkCheckGroup()">
        确定
      </el-button>
      <el-button type="primary" @click="CancelCheckGroup()">
        取消
      </el-button>
    </el-dialog>

    <!-- 选择设备的穿梭框 -->
    <el-dialog v-model="Status.dialogDeviceVisible" title="选择设备" width="800" :draggable="true">

      <el-transfer :titles="['所有设备', '已选择设备']" v-model="transfer.value" :data="transfer.data" :filterable="true" />

      <div class="center" style="margin-top: 10px;">
        <el-button type="primary" @click="OKCheckDevice()">
          确定
        </el-button>
        <el-button type="info" @click="hideDevice()">
          取消
        </el-button>
      </div>


    </el-dialog>

  </div>
</template>

<script setup lang="ts">

import api from '@/api/equipmentManagement/devicegroup/index';
import common from '@/utils/common'

interface Device {
  deviceName: string;
  devicePic: string;
  typeName: string;
  bindingStatus: string;
}


var searchTxt = ref('');  //左侧树筛选文本
var treeDataOrin = ref([]); //树控件的数据源
var grid = ref(null);

var cEdit = ref({ val: "", txt: "" });//当前正在编辑的节点数据

var checkNode = { val: '' };//记录被选中的节点

//全局状态控制
var Status = reactive({
  isEditTreeNode: false,//是否编辑节点
  isGjSearch: false,//是否显示高级筛选
  loading: false,
  confirm: {
    Visible: false,
    title: '',
    text: '',
    cancelCallback: '',
    OkCallback: '',
    showCancel: true
  },
  dialogGroupVisible: false,//是否显示选择分组的弹窗
  dialogDeviceVisible: false//是否显示选择设备的弹窗
});
//页码控件数据
var pagin = reactive({
  total: 0,
});
//右边的筛选条件
var GjSearchForm = reactive({
  deviceName: '',
  deviceType: "",
  netMode: "",
  pageNum: 1,
  pageSize: 10
});
//设备列表
var deviceList = ref<Device[]>();
//所有设备类型
var deviceTypes = reactive([]);

//穿梭框的数据和值
var transfer = reactive({
  value: [],
  data: []

});

window.confirm = function (text, OK, cancel, title) {
  let Cfg = {
    Visible: true,
    title: '提示',
    text: text ? text : '此操作不可逆，您确定这样做吗？',
    OkCallback: () => {
      Status.confirm.Visible = false;
      if (OK) {
        OK();
      }
    },
    showCancel: true,
    cancelCallback: () => {
      Status.confirm.Visible = false;
      if (cancel) {
        cancel();
      }
    }
  }

  Status.confirm = Cfg;
}

window.alert = function (text, OK, title) {

  let Cfg = {
    Visible: true,
    title: title ? title : '提示',
    text: text ? text : '不符合规则',
    OkCallback: () => {
      Status.confirm.Visible = false;
      if (OK) {
        OK();
      }
    },
    showCancel: false,
    cancelCallback: null
  }

  Status.confirm = Cfg;
}

var hideConfirm = function () {

  let Cfg = {
    Visible: false,
    title: '提示',
    text: "",
    cancelCallback: null,
    OkCallback: null
  }

  Status.confirm = Cfg;
}

var showloading = function () {
  // window.loadingIndex = ElLoading.service({ fullscreen: true })

  Status.loading=true;

}

var closeLoading = function () {
  // if (window.loadingIndex) {
  //   window.loadingIndex.close();
  // }

     Status.loading=false;
}
var hideloading = closeLoading;

function ResetQuery() {
  GjSearchForm.deviceType = "";
  GjSearchForm.netMode = "";
}
//查询某个节点的设备
var getDeviceList = () => {
  if (!checkNode.val) {
    pagin.total = 0;
    deviceList.value = [];
    return;
  }

  let para = {
    nodeCode: checkNode.val,
    pageIndex: GjSearchForm.pageNum,
    pageSize: GjSearchForm.pageSize,
    communicationMode: GjSearchForm.netMode,
    deviceType: GjSearchForm.deviceType,
    deviceName: GjSearchForm.deviceName
  }
  showloading();
  api.getNodeDevice(para).then((res) => {
    deviceList.value = res.rows;
    pagin.total = res.total;
  }).catch((ex) => {
    console.log("出现了异常", ex);
  }).finally(() => {
    hideloading();
  });


}
//树控件节点点击事件
var handleNodeClick = (node) => {
  
  if (checkNode.val == node.id) {
    return;
  }
  console.log("节点数据：", node.id);
  checkNode.val = node.id;
  getDeviceList();
}

//树控件筛选后显示的数据源
var treeData = computed(() => {
  let arr = api.treeNodeSearch(treeDataOrin.value, searchTxt.value, 'groupName', 'children');
  return arr;
});

//显示/隐藏高级筛选
var ToggleGjSearch = function () {
  Status.isGjSearch = !Status.isGjSearch;
}

//编辑节点
var editNode = (node) => {

  console.log("编辑节点：", node.data.value);
  cEdit.value.val = node.data.id;
  cEdit.value.txt = node.data.groupName;
  Status.isEditTreeNode = true;


  ElMessageBox.prompt('请输入名称', '编辑分组', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    inputValue: node.data.groupName
  })
    .then(({ value }) => {

      cEdit.value.txt = value;
      completeEdit(node);
    });
  //
}
//完成编辑
var completeEdit = (node) => {


  let now =common.DateFormat(new Date(), "yyyy-MM-dd HH:mm:ss");

  let newNode =
  {
    "createDept": node.data.createDept,//创建部门
    "createBy": node.data.createBy,//创建者
    "createTime": now,//创建时间
    "updateBy": node.data.updateBy,//更新者
    "updateTime": now,//更新时间
    "params": {
      "additionalProp1": "",
      "additionalProp2": "",
      "additionalProp3": ""
    },
    "id": node.data.id,//主键ID
    "groupName": cEdit.value.txt,//分组名称
    "status": 1,//状态：0-禁用，1-正常
    "parentId": node.data.parentId,//父分组ID
    "fullPath": node.data.fullPath,//完整分组路径
    "isDeleted": 0//删除标记：0-未删除，1-已删除
  };

  showloading();
  api.updateTreeName(treeDataOrin.value, newNode, cEdit.value.txt).then((res) => {
    if (res.code == 200) {
      alert("操作成功");
      RefreshTree();
    } else {
      alert(res.msg);
    }
  }).finally(() => {
    hideloading();
  });
  Status.isEditTreeNode = false;
}

//放弃编辑
var cancelEdit = (node) => {
  cEdit.value.val = "";
  cEdit.value.txt = "";
  Status.isEditTreeNode = false;
}

//删除节点
var delNode = (node) => {
  
  if (node.data.children && node.data.children.length > 0) {
    alert("节点包含子节点,不允许删除");
    return;
  }
  confirm("您确认删除’" + node.data.groupName + "’节点吗", () => {
    
    hideConfirm();

    api.delTreeNode(treeDataOrin.value, node.data.id).then((res) => {
      if (res.code == 200) {
        alert("操作成功");
        RefreshTree();
      } else {
        alert(res.msg);
      }
    });
  }, () => {
    hideConfirm();
  });



}

//增加节点
var addNode = (node) => {
  let title = '';
  if (node) {
    console.log("给节点新增子节点：", node.data.id);
    title = '添加子节点';
  }
  else {
    console.log("新增初级节点")
    title = '添加根节点'
  }
  let val = new Date().getTime();
  // let newNode = { value: val, txt: '' };
  let now =common.DateFormat(new Date(), "yyyy-MM-dd HH:mm:ss");



  ElMessageBox.prompt('请输入名称', title, {
    confirmButtonText: '确认',
    cancelButtonText: '取消'

  })
    .then(({ value }) => {
      
      if (!value) {
        alert("请输入分组名称");
        return;
      }
      let newNode =
      {
        "createDept": 0,//创建部门
        "createBy": 0,//创建者
        "createTime": now,//创建时间
        "updateBy": 0,//更新者
        "updateTime": now,//更新时间
        "params": {
          "additionalProp1": "",
          "additionalProp2": "",
          "additionalProp3": ""
        },
        "id": null,//主键ID
        "groupName": value,//分组名称
        "status": 1,//状态：0-禁用，1-正常
        "parentId": node ? node.data.id : null,//父分组ID
        "fullPath": val,//完整分组路径
        "isDeleted": 0,//删除标记：0-未删除，1-已删除

      };
      showloading();
      api.addTreeNode(treeDataOrin.value, newNode, node ? node.data.id : null).then((res) => {
        if (res.code == 200) {
          alert("操作成功");
          RefreshTree();
        } else {
          alert(res.msg);
        }
      }).catch((ex) => {
        console.log("ex=", ex);

      }).finally(() => {
        hideloading();
      });
    });
}




//树控件的自定义属性
var defaultProps = {
  children: 'children',
  label: 'groupName',
  parentId: "parentId"
}

var RowSelectionChange = (tr) => {
  
  console.log("行选中变化", tr);
  getSelectionRows();
};



var getSelectionRows = () => {

  if (grid.value) { // 检查ref是否已正确引用组件实例
    var selectedRows = grid.value.getSelectionRows(); // 获取选中行数据数组
    return selectedRows;
  }
  return [];
}


var RefreshTree = function () {
  api.getTreeData(searchTxt.value).then((res) => {
    treeDataOrin.value = res;

  });
}

//从分组中删除设备
var groupDelDevice = (row) => {

  let rows = [];//
  if (!row) {
    rows = getSelectionRows();
  } else {
    rows = [row];
  }
  if (rows.length == 0) {
    alert("请选择要删除的设备");
    return;
  }


  confirm("此操作不可逆,您确认要进行吗?", () => {
    showloading();
    let ids = rows.map(r => r.deviceId).join(",");
    api.groupDelDevice(checkNode.val, ids).then((res) => {
      if (res.code == 200) {
        alert("操作成功");
        getDeviceList();
      } else {
        alert(res.msg);
      }
    }).finally(() => {
      hideloading();
    });
  }, null, "警告");

}

var showDevice = () => {
  if(!checkNode.val){
    alert("请先选择分组");
    return;
  }
  Status.dialogDeviceVisible = true;
  //获取所有
  let promise1 = api.getNodeDevice({
    pageIndex: 1,
    pageSize: 9999,
    nodeCode: ""
  });
  //获取已选中的
  let promise2 = api.getNodeDevice({
    pageIndex: 1,
    pageSize: 9999,
    nodeCode: checkNode.val
  });

  cGroupAndDevice.deviceIds = [];
  transfer.value = [];

  Promise.allSettled([promise1, promise2]).then(res => {

    if (res[0].status == 'fulfilled') {
      let res1 = res[0].value;


      if (res1.code == 200) {
        let arr = res1.rows.map(item => ({
          key: item.deviceId,
          label: item.deviceName//,
          // disabled: item.groupId && item.groupId == checkNode.val ? false : item.groupId ? true : false
        }));

        transfer.data = arr;

      }

    }

    if (res[1].status == 'fulfilled') {
      let res2 = res[1].value;
      if (res2.code == 200) {
        
        let vals = res2.rows.map(item => item.deviceId);

        transfer.value = vals;

      }


    }
  });



}

//确认选择这些设备
var OKCheckDevice = () => {

  

  let arr = transfer.value.map(item => ({
    deviceId: item
  }));
  if (arr.length == 0) {
    alert("未选择任何设备");
    return;
  }
  hideDevice();
  cGroupAndDevice.deviceIds = arr;
  cGroupAndDevice.groupid = checkNode.val;
  deviceMoveGroup(cGroupAndDevice.groupid, cGroupAndDevice.deviceIds);
}

//隐藏选择设备
var hideDevice = () => {
  Status.dialogDeviceVisible = false;

}

var cGroupAndDevice = {
  groupid: '',
  deviceIds: []
};
//显示选择分组
var showCheckGroup = (type, row) => {
  let rows = [row];
  if (type == 'check') {
    rows = getSelectionRows();
  }

  if (rows.length == 0) {
    alert("请选择要移动的设备");
    return;
  }
  cGroupAndDevice.deviceIds = rows;
  Status.dialogGroupVisible = true;


  cGroupAndDevice.groupid = "";
}
//选中了某个分组
var CheckGroup = (item) => {

  cGroupAndDevice.groupid = item.id;
}

//确定选中某个分组
var OkCheckGroup = () => {
  if (!cGroupAndDevice.groupid) {
    alert("请先选择分组");
    return;
  }
  CancelCheckGroup();
  deviceMoveGroup(cGroupAndDevice.groupid, cGroupAndDevice.deviceIds);
}
//隐藏选择分组
var CancelCheckGroup = () => {
  Status.dialogGroupVisible = false
}
//将设备移动至分组
var deviceMoveGroup = (groupid, row) => {
  let rows = [];//
  if (!row) {
    rows = getSelectionRows();
  } else {
    if (Array.isArray(row)) {
      rows = row;
    } else {
      rows = [row];
    }

  }
  if (rows.length == 0) {
    alert("请选择要移动的设备");
    return;
  }


  // confirm("此操作不可逆,您确认要进行吗?", () => {
  showloading();
  let ids = rows.map(r => r.deviceId).join(",");
  api.deviceMoveGroup(groupid, ids).then((res) => {
    if (res.code == 200) {
      alert("操作成功");
      getDeviceList();
    } else {
      alert(res.msg);
    }
  }).finally(() => {
    hideloading();
  });
  // }, null, "警告");
}


  let timer;
  function InputSearch() {
    clearTimeout(timer);
    // 等待 500ms 无输入后执行查询
    timer = setTimeout(() => {
      getDeviceList();
    }, 500);
  }

onMounted(() => {
  RefreshTree();
  api.getDeviceTypeAll().then((res) => {
    if (res.code == 200) {
      deviceTypes = res.data.map(item => ({
        value: item.deviceTypeId,
        typeName: item.typeName
      }))
    }
  });

});
</script>


<style lang="scss" scoped>
.main .searchBar .btnReset {
  width: 76px;
  height: 32px;
  border-radius: 4px;
  background-color: #00000000;
  color: #027CFB;
  text-align: center;
  font-family: Microsoft YaHei;
  font-size: 14px;
  font-weight: 400;
  line-height: 32px;
  letter-spacing: 0px;
  border: 1px solid rgb(2, 124, 251);
  cursor: pointer;
}

.main .searchBar .btnSearch {
  /* 组合 454 */
  width: 76px;
  height: 32px;
  border-radius: 4px;
  background-color: #027CFB;
  color: #FFFFFF;
  text-align: center;
  font-family: Microsoft YaHei;
  font-size: 14px;
  font-weight: 400;
  line-height: 32px;
  letter-spacing: 0px;
  border: none;
  margin-right: 15px;
  cursor: pointer;
}

.main .searchBar {
  width: 100%;
  height: 50px;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  justify-content: space-between;
  align-items: center;
}

.main .toolBar .rightSearch {
  width: 295px;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  justify-content: space-between;
  align-items: center;
}


.main .toolBar .gjSearch {
  /* 矩形 155 */
  width: 85px;
  height: 32px;
  box-sizing: border-box;
  border: 1px solid rgba(2, 124, 251, 1);
  border-radius: 4px;
  color: rgba(2, 124, 251, 1);
  cursor: pointer;
  font-family: Noto Sans SC;
  font-size: 14px;
  font-weight: 400;
  line-height: 32px;
  letter-spacing: 0px;
  text-align: center;
}

.main .toolBar .searchContent {
  width: 200px;
  height: 32px;
  border: 1px solid rgba(189, 198, 215, 1);
  border-radius: 4px;
}

.main .toolBar .serchTxt {
  border: none;
  width: 175px;
  height: 100%;

}

.main .toolBar .btnAdd {
  background-color: #027CFB;
  color: #FFFFFF;
  width: 105px;
  height: 32px;
  text-align: center;
  font-family: Microsoft YaHei;
  font-size: 14px;
  font-weight: 400;
  line-height: 32px;
  letter-spacing: 0px;
  cursor: pointer;
}

.main .toolBar {
  width: 100%;
  height: 35px;
  overflow: hidden;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  justify-content: space-between;
  align-items: flex-start;
  border-bottom: 1px solid rgba(235, 238, 248, 1);
}

.nodeInput {
  height: 30px;
  line-height: 30px;
  border: 1px solid rgb(189, 198, 215);
  border-radius: 4px;
  box-sizing: border-box;
}

.red {
  color: #FF0000;
}

.green {
  color: #0ed50e;
}

.custom-tree-node {
  width: 100%;
  height: 40px;
  line-height: 40px;
  display: flex;
  flex-direction: row;
  align-content: center;
  flex-wrap: nowrap;
  justify-content: space-between;
  align-items: center;
}

.custom-tree-node.active {
  background: #80bcf966 !important;
  color: #FFFFFF;
}


.custom-tree-node .iconContent {
  width: 60px;
  height: 100%;

  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  justify-content: space-evenly;
  align-items: center;

}

.custom-tree-node .iconContent .icon {
  width: 18px;
  height: 18px;
  visibility: hidden;
}

.custom-tree-node-Edit .iconContent .icon {
  visibility: visible !important;
}

.custom-tree-node:hover .iconContent .icon {
  visibility: visible;
}

.leftTree .treeBold {
  font-weight: 700;
}

.leftTree .treeContent::-webkit-scrollbar {
  display: none;
}

.leftTree .treeContent {
  margin-top: 10px;
  height: calc(100% - 95px);
  overflow: scroll;
  box-sizing: border-box;
}

.leftTree .Search .txt::placeholder {
  color: rgba(189, 198, 215, 1);

  font-family: Microsoft YaHei;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0px;
  text-align: left;
}

.leftTree .Search .txt {
  width: 100%;
  height: 100%;
  border: none;
  background-color: #00000000;
  text-indent: 5px;
  line-height: 36px;
  color: rgb(96, 98, 102);
}

.leftTree .Search {
  width: 100%;
  margin-top: 10px;
  height: 36px;
  border: 1px solid rgba(189, 198, 215, 1);
  border-radius: 4px;
  box-sizing: border-box;
}

.leftTree .head .nodeEdit {
  color: rgba(2, 124, 251, 1);
  cursor: pointer;
  font-family: Microsoft YaHei;
  font-size: 14px;
  font-weight: 400;
  line-height: 18px;
  letter-spacing: 0px;
  text-align: left;
}

.leftTree .head .title {
  color: rgba(56, 64, 79, 1);

  font-family: Microsoft YaHei;
  font-size: 14px;
  font-weight: 700;
  line-height: 18px;
  letter-spacing: 0px;
  text-align: left;
}

.leftTree .head {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: 40px;
  border-bottom: 1px solid rgba(235, 238, 248, 1);
}

.fleft {
  float: left;
}

.fright {
  float: right;
}

.clear {
  clear: both;
}

.center {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-content: center;
  align-items: center;
  justify-content: center;
}

.displayNone {
  display: none !important;
}

input:focus {
  outline: none;
}

.H100 {
  height: 100%;
}

.content {
  width: 100%;
  min-height: calc(100vh - 84px);
  height: calc(100vh - 84px);
  background-color: #FFFFFF;
  font-size: 16px;
  box-sizing: border-box;
  padding: 8px 20px;
  font-family: 'Microsoft YaHei';
}

.leftTree {
  width: 18%;
  height: 100%;
  border-radius: 4px;
  box-shadow: 0px 0px 6px 0px rgba(0, 34, 96, 0.1);
  background: rgba(255, 255, 255, 1);
  margin-right: 15px;
  box-sizing: border-box;
  padding: 12px 13px;
}

.main {
  width: calc(82% - 15px);
  height: 100%;
  border-radius: 4px;
  box-shadow: 0px 0px 6px 0px rgba(0, 34, 96, 0.1);
  background: rgba(255, 255, 255, 1);
  box-sizing: border-box;
  padding: 15px;
}

.moveDev {
  margin-right: 10px;
  color: rgba(2, 124, 251, 1);

  font-family: Noto Sans SC;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0px;
}

.delDev {
  color: rgba(224, 52, 52, 1);

  font-family: Noto Sans SC;
  font-size: 12px;
  font-weight: 400;

  letter-spacing: 0px;

}

.gridTool {
  padding-bottom: 10px;
}

:deep .el-tree-node__content {
  height: auto !important;
}
</style>
