<!--
 * @Author: Jone
 * @Date: 2022-4-28 09:11:26
 * @LastEditors: Jone
 * @LastEditTime: 2022-07-12 09:22:25
 * @FilePath: /frontend/lib/components/MdCustomModule.vue
 * @Description: 元素（数据元、值域、统计指标)列表,数据集列表   MdElementList
 *
 * Copyright (c) 2022 by 青岛百洋智能科技股份有限公司, All Rights Reserved.
-->
<template>
  <div class="oecp-md-element-list height100 flex flex-direction-column">
    <!-- top start -->
    <div style="width:100%">
      <el-row class="pos-style1">
        <el-col :span="18">
          <template v-if="showGoBack">
            <el-page-header
              @back="goBack"
              title=''
            >
              <div slot="content">
                <template v-if="!!$slots.title">
                  <slot name="title"></slot>
                </template>
                <div
                  v-else-if="!!title"
                  class="title-style"
                >{{title}}</div>
              </div>
            </el-page-header>
          </template>
          <template v-else>
            <template v-if="!!$slots.title">
              <slot name="title"></slot>
            </template>
            <div
              v-else-if="!!title"
              class="title-style"
            >
              <img src="../common/img/edit.png" />
              {{title}}
              <el-input
                v-model="form.name"
                @clear="getList"
                placeholder="请输入内容"
                @keyup.enter.native="getList"
                clearable
              >
                <el-button
                  slot="append"
                  @click="getList"
                  icon="el-icon-search"
                />
              </el-input>
            </div>
          </template>
        </el-col>
      </el-row>
    </div>
    <!-- top end -->

    <!-- 列表 start -->
    <div class="flex templateListBox">
      <div
        class="templetList newAdd flex flex-center"
        @click="addModuleVisible = true"
        v-oecp-auth:[{type:stateType}]="'templateList.add'"
      >
        <i class="el-icon-circle-plus"></i>新增模板
      </div>
      <div
        v-for="(val,index) in listData"
        :key="index"
        class="templetList flex flex-start flex-direction-column"
        @mouseenter="closeIndex = index"
        @mouseleave="closeIndex = null"
      >
        <div
          class="top flex flex-start"
          @click="handleRowClick(val,true)"
        >
          <p>
            {{val.name}}
          </p>
        </div>
        <div class="bottom">
          <div class="code flex flex-between">
            <span>Code</span>
          </div>
          <div class="bottom-templetInfo flex flex-between">
            <span class="modelCode">{{val.code || '暂无'}}</span>
          </div>
          <div class="bottom-templetTime flex flex-start">
            <span>内部编码</span>
            <span
              class="codeInner"
              :title="val.internalCode"
            >{{val.internalCode}}</span>
          </div>
          <div class="bottom-templetTime flex flex-start">
            <span>更新时间</span>
            <span
              class="codeInner"
              :title="val.updateDate"
            > {{format(val.updateDate)}}</span>
          </div>
        </div>
        <div class="btnBox flex">
          <el-button
            v-oecp-auth:[{type:stateType}]="'templateList.row.edit'"
            type="text"
            @click="handleRowClick(val,true)"
          >编辑</el-button>
          <el-button
            v-oecp-auth:[{type:stateType}]="'templateList.row.sql'"
            type="text"
            @click="generateSQL(val)"
          >生成SQL</el-button>
        </div>
        <div
          class="closeDiv"
          v-if="closeIndex == index"
        >
          <img
            src="../common/img/delete.png"
            @click="delHandle(val)"
          />
        </div>
      </div>
    </div>
    <div style="padding:10px 0;width: 100%;justify-content: flex-end;display: flex;max-width: 1100px;margin: 0 auto;">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="currentPage"
        :page-sizes="[14, 29, 59, 164]"
        :page-size="14"
        layout="total, sizes, prev, pager, next, jumper"
        :total="pagination.total"
      >
      </el-pagination>
    </div>

    <!-- 列表 end -->

    <!-- 新增 start -->
    <el-dialog
      title="新建模板"
      :visible.sync="addModuleVisible"
      width="30%"
    >
      <el-form
        :model="addModuleForm"
        :rules="addModuleRules"
        ref="addModuleForm"
        label-width="100px"
        class="demo-addModuleForm"
      >
        <el-form-item
          label="名称"
          prop="name"
        >
          <el-input
            v-model="addModuleForm.name"
            size="small"
          ></el-input>
        </el-form-item>
        <el-form-item
          label="内部标识符"
          prop="internalCode"
        >
          <el-input
            v-model="addModuleForm.internalCode"
            size="small"
          ></el-input>
        </el-form-item>
      </el-form>
      <span
        slot="footer"
        class="dialog-footer"
      >
        <el-button
          @click="addModuleVisible = false"
          size="small"
        >取 消</el-button>
        <el-button
          type="primary"
          @click="submitForm('addModuleForm')"
          size="small"
        >确 定</el-button>
      </span>
    </el-dialog>
    <!-- 新增 end -->

    <!-- 删除 start -->
    <el-dialog
      title="提示"
      :visible.sync="delVisible"
      width="400px"
      :before-close="handleClose"
      class="delDialog"
      top="40vh"
    >
      <span><i
          class="el-icon-delete"
          style="color: red;padding: 0 2px 0 20px;"
        ></i> 确定要删除{{delInfo.name}}？</span>
      <span
        slot="footer"
        class="dialog-footer"
      >
        <el-button
          @click="delVisible = false"
          size="small"
        >取 消</el-button>
        <el-button
          type="primary"
          size="small"
          @click="delConfirm"
        >确 定</el-button>
      </span>
    </el-dialog>
    <!-- 删除 end -->

    <!-- 查询SQL start -->
    <el-dialog
      title="生成的SQL语句"
      :visible.sync="sqlVisible"
      width="30%"
    >
      <el-input
        type="textarea"
        :value="sqlMsg"
        :rows="20"
      ></el-input>
      <span
        slot="footer"
        class="dialog-footer"
      >
        <el-button
          type="primary"
          @click="sqlVisible = false"
          size="small"
        >确 定</el-button>
      </span>
    </el-dialog>
    <!-- 查询SQL end -->
  </div>
</template>
<script>
import OptionsMixin from '../mixins/OptionsMixin'
import RouterMixin from '../mixins/RouterMixin'
import EventMixin from '../mixins/EventMixin'
import get from 'lodash/get'
import isEmpty from 'lodash/isEmpty'
import { fetchApi } from '../common/apis.js'
import { format, clone, parsePromise } from '../common/utils.js'
import debounce from 'lodash/debounce'
import isFunction from 'lodash/isFunction'
import isString from 'lodash/isString'
import isArray from 'lodash/isArray'
import isObject from 'lodash/isObject'

let extQuery = { ids: [], extNameList: [] } // 查询条件,放在外面规避内部使用循环报错

export default {
  mixins: [OptionsMixin, RouterMixin, EventMixin],
  props: {
    title: { type: [String, null], default: '' },
    type: { type: [String, Number, null], default: '2' },
    setId: { type: [String, null], default: null },
    showTabs: { type: Boolean, default: false },
    showImport: { type: Boolean, default: false },
    showSelection: { type: Boolean, default: false },
    showAdd: { type: Boolean, default: false },
    addBtnTitle: { type: [String, null], default: null },
    showSelectAllTag: { type: Boolean, default: false },
    showGoBack: { type: Boolean, default: false }, // 显示返回
    types: { type: [Array, null], default: null }, // 显示的所有类型
    showRowAction: { type: Boolean, default: true },
    includeSys: { type: [String, null], default: '' }, // 集合包含数据集标示；用于配合业务使用时权限处理
  },
  computed: {
    importButtonDisabled: function () {
      let list = get(this.getMbOptionVar('typeConfig'), 'list') || []
      let { stateType: type } = this
      let cfg = list.find(o => o.type === type) || {}
      return this.selected.length === 0 || !cfg.showImport
    },
    showRowSelection: function () {
      return this.showImport || this.showSelection
    },
  },
  watch: {
    type(val) {
      this.stateType = val
    },
    showTabs(val) {
      this.stateShowTabs = val
    },
    stateType() {
      this.initAndLoad()
    },
    tags: {
      handler: function (val) {
        this.getList()
      },
      deep: true,
    },
  },
  data() {
    return {
      closeIndex: null,
      loading: false,
      importDialogVisible: false,
      stateType: '',
      stateShowTabs: this.showTabs,
      tags: [], // 选中的分类标签
      showRowBtnText: false,
      form: { name: '' },
      pagination: {
        total: 0,
        page: 1,
        pageSize: 14,
        pageSizes: [14, 29, 59, 164],
      },
      currentPage: 1,
      listData: [],
      selected: [],
      tableData: [],
      defaultColumns: [
        { prop: 'name', label: '名称' },
        { prop: 'code', label: '编码' },
        { prop: 'sourceFileCode', label: '来源文件编码' },
        { prop: 'sourceCode', label: '来源标识符' },
      ],
      columns: [],
      actionColumn: { label: '操作', width: 100 },
      elementTypeKv: {}, // key:类型 value: 名称
      extData: {}, // 扩展信息
      debounceGetExtData: debounce(this.getExtData, 250),
      extLoading: false,

      // new
      addModuleVisible: false, // 新增模态框
      addModuleForm: {
        // 新增提交的表单
        name: '',
        internalCode: '',
      },
      addModuleRules: {
        name: [
          { required: true, message: '请输入名称', trigger: 'blur' },
          { min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' },
        ],
        internalCode: [
          { required: true, message: '请输入内部标识符', trigger: 'blur' },
          { min: 1, max: 50, message: '长度在 1 到 50 个字符', trigger: 'blur' },
        ],
      },
      delVisible: false, //删除模态框
      delInfo: {}, //要删除的信息
      sqlVisible: false, //SQL模态框
      sqlMsg: '',
    }
  },
  methods: {
    handleClose() {
      this.delVisible = false
    },
    // 删除提示
    delHandle(val) {
      this.delInfo = val
      this.delVisible = true
    },
    // 确认删除
    delConfirm() {
      let url = '/set/delete'
      let that = this
      let params = {
        id: this.delInfo.id,
      }
      fetchApi.call(that, url, params).then(function (res = []) {
        that.$message({
          message: '删除成功~',
          type: 'success',
        })
        that.delVisible = false
        that.handleCurrentChange(1)
      })
    },
    // 生成SQL
    generateSQL(val) {
      let url = '/tables/genSqlByDataset'
      let that = this
      let params = {
        id: val.id,
      }
      fetchApi.call(that, url, params).then(function (res = []) {
        // 显示的数据只是展示第一条即可
        that.$message({
          message: '生成成功~',
          type: 'success',
        })
        setTimeout(() => {
          that.sqlMsg = res[0]
          that.sqlVisible = true
        }, 500)
      })
    },
    format(val) {
      return format(val)
    },
    handleSizeChange(val) {
      this.pagination.page = 1
      this.pagination.pageSize = val
      this.getList()
    },
    handleCurrentChange(val) {
      this.pagination.page = val
      this.getList()
      console.log(`当前页: ${val}`)
    },
    // 提交新增模板数据 2022年4月28日17:10:新建模板
    submitForm(formName) {
      this.$refs[formName].validate(valid => {
        let that = this
        let url = '/set/save'
        let params = { ...that.addModuleForm, type: '3' }
        if (valid) {
          fetchApi.call(that, url, params).then(function (res = []) {
            that.$message({
              message: '创建成功~',
              type: 'success',
            })
            that.addModuleVisible = false
            that.handleCurrentChange(1)
          })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    },

    // 编辑和查看 再加上新增 2022年4月28日17:28:13
    handleRowClick(data, editable) {
      console.log(data)
      let { stateType: type } = this
      let cfg = this.getTypeConfig()
      console.log(cfg)
      // let { component = 'set' } = cfg
      let { id } = data
      let title = '修改' + cfg.name
      this.goto(
        {
          componentName: 'md-edit-module',
          attrs: {
            id,
            title,
            type,
            editable: !!editable,
            showSubset: true,
            showElement: true,
            showCategory: true,
            showGoBack: true,
          },
          history: this.getCurrentRouteCfg(),
        },
        true,
        true,
      )
    },

    // 历史记录
    getCurrentRouteCfg() {
      let current = clone(this.$OecpMetaDataEventBus.component)
      return { ...current, attrs: { ...current.attrs } }
      // return { ...current, attrs: { ...current.attrs, page: this.pagination.page, type: this.stateType } }
    },
    getExtData() {
      let that = this
      let { ids, extNameList } = extQuery
      let { component = 'set' } = this.getTypeConfig()
      let url = component === 'element' ? '/element/extList' : '/set/extList'
      this.extLoading = true
      fetchApi.call(that, url, { ids, extNameList }).then(function (res = []) {
        let extData = {}
        res.forEach(function (item) {
          let { extName, parentId, extValue } = item
          extData[`${parentId}_${extName}`] = extValue
        })
        that.extData = { ...that.extData, ...extData }
        that.extLoading = false
      })
    },
    pushQuery(id = '', extName = '') {
      if (!id && !extName) return
      let key = `${id}_${extName}`
      // 会出现循环调用，添加判断规避死循环
      if (this.extData.hasOwnProperty(key)) return
      this.extData[key] = ''
      extQuery = {
        ids: [...new Set([...extQuery.ids, id])],
        extNameList: [...new Set([...extQuery.extNameList, extName])],
      }
      this.debounceGetExtData()
    },
    extFileColumnRender(h, data, extName = '') {
      let { _self: self, row = {} } = data
      if (isEmpty(row) || !extName || !row.id) return h('div')
      this.pushQuery(row.id, extName)
      let obj = self.extData[`${row.id}_${extName}`]
      if (obj) {
        obj = isString(obj) ? JSON.parse(obj) : obj
        obj = isArray(obj) ? obj : [obj]
        return h(
          'div',
          null,
          obj.map(function (item) {
            return h(
              'el-link',
              {
                domProps: { target: '_blank' },
                attrs: { type: 'primary', href: item.url },
              },
              item.name,
            )
          }),
        )
      } else {
        return h('div', { domProps: { innerHTML: self.extData[`${row.id}_${extName}`] } })
      }
    },
    extColumnRender(h, data, extName = '', customRender) {
      this.loadExtData(h, data, extName, customRender)
    },
    loadExtData(h, data, extName = '', customRender) {
      let { _self: self, row = {} } = data
      if (isEmpty(row) || !extName || !row.id) return h('div')
      this.pushQuery(row.id, extName)
      if (customRender && isFunction(customRender)) {
        return customRender(h, data, extName)
      } else {
        return h('div', { domProps: { innerHTML: self.extData[`${row.id}_${extName}`] } })
      }
    },
    getTypeConfigList() {
      return get(this.getMbOptionVar('typeConfig'), 'list') || []
    },
    getTypeConfig() {
      let { stateType: type } = this
      console.log('this.getTypeConfigList()', this.getTypeConfigList())
      return this.getTypeConfigList().find(o => o.type === type)
    },
    handleTagRootChange(type) {
      this.stateType = type
    },
    handleAddClick() {
      this.handleRowClick({}, true)
    },
    handleRowChange(selection, row) {
      if (selection.length && selection.findIndex(o => o.id === row.id) !== -1) {
        // 新增
        this.selected.push(row)
      } else {
        // 反选
        let idx = this.selected.findIndex(o => o.id === row.id)
        idx !== -1 && this.selected.splice(idx, 1)
      }
      this.$emit('change', this.selected)
    },
    handleRowChangeAll(selection) {
      let that = this
      if (selection.length === 0) {
        // 反选
        that.selected.length &&
          this.tableData.forEach(row => {
            let idx = that.selected.findIndex(o => o.id === row.id)
            idx !== -1 && that.selected.splice(idx, 1)
          })
      } else {
        // 全选
        this.tableData.forEach(row => {
          that.selected.findIndex(o => o.id === row.id) === -1 && that.selected.push(row)
        })
      }
      this.$emit('change', this.selected)
    },
    checkElementUsed(extValue, extName, component) {
      let that = this
      let alreadyUsedErr = '数据已被引用，无法删除'
      if (component === 'element') {
        return new Promise(function (resolve, reject) {
          let query = { extName, extValue }
          fetchApi.call(that, '/element/findExtCount', query).then(function (rs) {
            if (rs.count === 0) return resolve()
            that.$message.error(alreadyUsedErr)
            reject(new Error(alreadyUsedErr))
          })
        })
      } else {
      }
    },
    handleRowDel(data) {
      let that = this
      let cfg = this.getTypeConfig()
      let { id } = data
      let { component = 'set' } = cfg
      let url = component === 'element' ? '/element/delete' : '/set/delete'
      this.$confirm(`此操作将永久删除该${cfg.name}, 是否继续?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(function () {
        let beforeElementDelete = get(that, '$OecpMetaDataConfig.beforeElementDelete')
        let dfd = null
        if (isFunction(beforeElementDelete)) {
          let res = beforeElementDelete.call(that, data, that.stateType)
          dfd = parsePromise(res)
        } else if (isString(beforeElementDelete)) {
          dfd = that.checkElementUsed(id, beforeElementDelete, 'element')
        } else if (isObject(beforeElementDelete) || isArray(beforeElementDelete)) {
          let typeList = []
          let { stateType: type } = that
          if (isObject) {
            for (const key in beforeElementDelete) {
              typeList.push({ type: key, extName: beforeElementDelete[key] })
            }
          } else {
            typeList = beforeElementDelete
          }
          let item = beforeElementDelete.find(item => item.type === type)
          if (item) {
            let { component = 'element', extName } = item
            if (item.component === 'set') {
            } else {
              dfd = that.checkElementUsed(id, extName, component)
            }
          } else {
            dfd = Promise.resolve()
          }
        } else {
          dfd = Promise.resolve()
        }
        dfd.then(function (rs) {
          fetchApi
            .call(that, url, { id })
            .then(function () {
              that.$message({ type: 'success', message: '删除成功!' })
              let { page } = that.pagination
              if (that.tableData.length === 1 && page > 1) {
                that.pagination = { ...that.pagination, page: page - 1 }
              } else {
                that.getList()
              }
            })
            .catch(() => {
              // 统一 使用 defaultFail 做信息提示。这里只能做回滚等业务
              // that.$message({ type: 'error', message: '删除失败!' })
            })
        })
      })
    },
    initAndLoad() {
      this.tags = []
      this.selected = []
      let { stateType: type } = this
      let cfg = this.getTypeConfig()
      let { component = 'set' } = cfg
      let tableCfg = this.getMbOptionVar(`${component}TableConfig${type}`)
      let allColumns = [...this.defaultColumns, ...(get(tableCfg, 'ext') || [])]
      let columns = []
      let actionColumn = { label: '操作', width: 100 }
      allColumns.forEach(item => {
        if (item.prop !== 'action') {
          columns.push(item)
        } else {
          actionColumn = { ...item }
        }
      })
      this.columns = columns
      this.actionColumn = actionColumn
      this.pagination.page = 1
      this.getList()
    },
    getList() {
      let that = this
      if (this.loading) return false
      this.loading = true
      let { pageSize, page } = this.pagination
      let url = '/template/pageList'
      let query = {
        pageSize,
        page,
        // parentId: '0',
        name: this.form.name,
        isSys: '0',
      }
      that.extData = {}
      extQuery = { ids: [], extNameList: [] }
      fetchApi
        .call(this, url, query)
        .then(function (res) {
          console.log('res', res)
          that.listData = res.records
          that.pagination = { ...that.pagination, total: get(res, 'total') }
        })
        .catch(() => {
          that.pagination = { ...that.pagination, total: 0 }
          that.tableData = []
        })
        .finally(() => {
          that.backfillSelectedRow()
          that.loading = false
        })
    },
    backfillSelectedRow() {
      // 勾选数据回填
      if (this.selected.length === 0 || this.tableData.length === 0 || !this.setId) return false
      let that = this
      this.tableData.forEach(function (row) {
        if (that.selected.findIndex(o => o.id === row.id) !== -1) {
          that.$refs.table.toggleRowSelection(row, true)
        }
      })
    },
  },
  created() {
    this.getList()
    let list = this.getTypeConfigList()
    this.stateType = this.type || get(list, '[0].type')
    this.elementTypeKv = list.reduce(function (obj, current) {
      return { ...obj, [current.type]: current.name }
    }, {})
  },
}
</script>
<style scoped>
.mb5 {
  margin-bottom: 5px;
}
.ml5 {
  margin-left: 5px;
}
.mt-2 {
  margin-top: -2px;
}
.pos-style1 {
  background: #ebeff2;
  padding: 10px 12px;
}
.title-style {
  /* padding-top: 6px; */
  font-size: 18px;
  /* font-weight: 600; */
  display: flex;
}
.title-style img {
  height: 23px;
  width: 23px;
  margin-right: 10px;
}
.templateListBox {
  border-radius: 6px;
  padding: 12px;
  flex: 1;
  overflow: auto;
  align-content: baseline;
  width: 1100px;
  margin: 0 auto;
  /* background: ; */
}
.templetList {
  width: 180px;
  height: 220px;
  background: linear-gradient(#f5f8ff, #e5eeff); /* 标准的语法 */
  border: 1px solid #a8c3ff;
  border-radius: 4px;
  padding: 8px 7px 0;
  position: relative;
  margin-right: 20px;
  text-align: center;
  color: #a3a3a3;
  font-size: 16px;
  cursor: pointer;
  font-family: 微软雅黑;
  margin-bottom: 20px;
  position: relative;
}
.templetList .closeDiv {
  position: absolute;
  top: 0;
  right: 0;
}
.templetList .closeDiv img {
  height: 36px;
  width: 36px;
}
.templetList:hover {
  box-shadow: 0 2px 6px 0 rgb(0 0 0 / 5%);
}
.templetList .top {
  height: 70px;
  padding: 0 8px 20px;
  box-sizing: border-box;
  width: 100%;
  font-size: 14px;
  color: #303030;
  letter-spacing: 1.05px;
  background: url('../common/img/inToDetail.png') no-repeat 100% 100%;
  background-color: #fff;
  background-size: 35px 26px;
  word-break: break-all;
  text-overflow: ellipsis;
  display: -webkit-box;
  align-content: flex-start;
  /*! autoprefixer: off */
  -webkit-box-orient: vertical;
  /* autoprefixer: on */
  -webkit-line-clamp: 2;
  overflow: hidden;
  border-radius: 6px;
}

.templetList .top p {
  padding: 0;
  height: 40px;
  line-height: 20px;
  text-align: justify;
  word-break: break-all;
  text-overflow: ellipsis;
  display: -webkit-box;
  align-content: flex-start;
  /*! autoprefixer: off */
  -webkit-box-orient: vertical;
  /* autoprefixer: on */
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.templetList .top:hover {
  background-color: #fff;
  background-size: 35px 26px;
}
.templetList .bottom {
  cursor: auto;
  width: 100%;
  height: '';
}
.templetList .bottom .code {
  padding-top: 14px;
  color: #323232;
  font-size: 14px;
}
.templetList .bottom .bottom-templetInfo {
  color: #303030;
  font-size: 16px;
  padding: 4px 0 6px;
}
.modelCode {
  display: inline-block;
  position: relative;
  padding-bottom: 6px;
}
.modelCode:after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 1px;
  background: linear-gradient(left, #6d99ff, #d4e0ff); /* 标准的语法 */
}
.templetList .bottom .bottom-templetTime {
  font-size: 12px;
  color: #909090;
  letter-spacing: 0.75px;
  padding: 0px;
  padding-top: 4px;
  margin: 0px;
}
.templetList .bottom .bottom-templetTime .codeInner {
  display: inline-block;
  text-align: start;
  flex: 1;
  padding-left: 10px;
  word-break: break-all;
  text-overflow: ellipsis;
  display: -webkit-box;
  align-content: flex-start;
  /*! autoprefixer: off */
  -webkit-box-orient: vertical;
  /* autoprefixer: on */
  -webkit-line-clamp: 1;
  overflow: hidden;
}
.btnBox {
  width: 100%;
  width: 100%;
  position: relative;
}
.btnBox:before {
  content: '';
  position: absolute;
  right: 50%;
  top: 25%;
  height: 50%;
  width: 1px;
  background: #dddddd;
}
.btnBox button {
  flex: 1;
}

.newAdd {
  border: 1px dashed #6091ff;
  background: #fff;
  color: #2468f2;
  flex-direction: column;
}
.newAdd:hover {
  box-shadow: 0 2px 8px 0 rgb(0 0 0 / 15%);
  background: #fafcff;
  border-radius: 5px;
}
.newAdd .el-icon-circle-plus {
  font-size: 50px;
  color: #d0e0ff;
}
.handleIcon {
  cursor: pointer;
  transform: rotate(90deg);
}
.handleIcon:hover {
  color: #409eff;
}
.delDialog /deep/.el-dialog__body {
  padding: 0 20px;
}
.flex {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  flex-wrap: wrap;
}
.flex-start {
  justify-content: flex-start;
  align-items: flex-start;
}
.flex-between {
  justify-content: space-between;
}
.flex-center {
  justify-content: center;
  align-items: center;
}
.flex-direction-column {
  flex-direction: column;
  flex-wrap: nowrap;
}

.height100 {
  height: 100%;
  flex: 1;
  overflow: auto;
}

ul,
li {
  list-style: none;
  padding: 0px;
  margin: 0px;
}

/* 滚动条样式 start */
::-webkit-scrollbar {
  width: 4px; /* 滚动条宽度， width：对应竖滚动条的宽度  height：对应横滚动条的高度*/
  background: #fff;
}
/*定义滚动条轨道（凹槽）样式*/
::-webkit-scrollbar-track {
  -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0); /* 较少使用 */
  border-radius: 3px;
}
/*定义滑块 样式*/
::-webkit-scrollbar-thumb {
  border-radius: 3px;
  height: 100px; /* 滚动条滑块长度 */
  background-color: #dbdbdb;
}
/* 滚动条样式 end */

/* 超出一行省略号 start */
.wordSingle {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}
/* 超出一行省略号 end */

/* 超出两行省略号 start */
.wordDouble {
  white-space: nowrap;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* 超出两行省略号 end */
/deep/.el-input-group--append .el-input__inner {
  border-top-left-radius: 30px !important;
  border-bottom-left-radius: 30px !important;
  height: 36px !important;
}
/deep/.el-input-group__append {
  padding-right: 8px;
  border-top-right-radius: 30px !important;
  border-bottom-right-radius: 30px !important;
}
/* title start */
.el-input-group {
  border-radius: 30px;
  overflow: hidden;
  border: 1px solid #ddd;
}
/deep/.el-input-group--append .el-input__inner,
/deep/.el-input-group__prepend {
  border-top-left-radius: 30px !important;
  border-bottom-left-radius: 30px !important;
  height: 36px !important;
  border: none;
}
/deep/.el-input-group--prepend .el-input__inner,
/deep/.el-input-group__append {
  padding-right: 8px;
  border-top-right-radius: 30px !important;
  border-bottom-right-radius: 30px !important;
  background-color: #fff;
  border: none;
}
/deep/.el-icon-search {
  color: #2468f2 !important;
  font-size: 20px;
}
/* title end */
.oecp-md-element-list {
  background-color: #fff;
}
.title-style {
  padding-bottom: 0;
  display: flex;
  align-items: center;
  font-size: 18px;
}

.el-input-group {
  border-radius: 30px;
  overflow: hidden;
  /* border: 1px solid #ddd; */
  width: 300px;
  margin-left: 15px;
}
.el-button--text {
  color: #2468f2;
}
.el-button--text:hover {
  color: #125df1;
}
</style>
