<template>
  <div class="header-actions" v-if="getActionList.length != 0">
    <div class="overflow-box">
      <el-button
        v-for="(item, index) in getActionList"
        :key="index"
        :type="item.type || 'primary'"
        :plain="item.plain ? item.plain : index != 0"
        v-bind="getHeaderActions(item)"
        @click="item.action"
        :disabled="item.disabled || false"
      >
        {{ item.text }}
      </el-button>
    </div>
  </div>
  <!-- statWarpHeight > 200 &&  -->
  <div
    class="stat-warp"
    v-if="statConfig.length != 0"
    :class="isMore ? 'show-more' : ''"
  >
    <div class="title">
      <select
        v-model="statSelectVal"
        v-if="statConfig.length > 1"
        @change="changeStatData"
      >
        <option :value="index" v-for="(i, index) in statConfig" :key="index">
          {{ i.label }}
        </option>
      </select>
      <div v-if="statConfig.length === 1">{{ statConfig[0].label }}</div>
    </div>
    <!-- v-if="statWarpHeight > 200" -->
    <div class="more-btn"  @click="isMore = !isMore" >
      <span>
        <i v-if="!isMore" class="iconfont icon-btn_xiala22"></i>
        <i v-else class="iconfont icon-btn_shouqi22"></i>
        
      </span>
    </div>
    <ul id="statWarp">
      <li
        v-show="!i.data"
        :class="'theme' + i.type"
        v-for="(i, index) in statConfig[statSelectVal].data"
        :key="index"
        @click="i.click ? i.click(i, index) : ''"
        :style="i.click ? 'cursor: pointer' : ''"
      >
        <div class="label">{{ i.label }}</div>
        <div class="num">{{ i.num }}</div>
      </li>
      <li
        v-show="i.data"
        v-for="(i, index) in statConfig[statSelectVal].data"
        :key="index"
        class="multi-data"
        :class="'theme' + i.type"
        @click="i.click ? i.click(i, index) : ''"
        :style="i.click ? 'cursor: pointer' : ''"
      >
        <div class="label">{{ i.label }}</div>
        <div class="num-warp">
          <div class="num-box" v-for="(j, jindex) in i.data" :key="jindex">
            <div class="num-small" :style="'color:' + j.color">
              {{ j.num }}
            </div>
            <div class="label-small">{{ j.label }}</div>
          </div>
        </div>
      </li>
    </ul>
  </div>
  <div class="table-list-container by-table" v-loading="loading">
    <!-- v-if="!hideHeader" -->
    <header v-if="false" class="header">
      <h2>{{ title }}</h2>
    </header>
    <div class="by-search" v-if="!hideSearch">
      <div style="display: flex">
        <div
          class="by-dropdown"
          v-for="(i, index) in selectConfigCopy"
          :key="i.prop"
          style="margin-right: 10px"
        >
          <div class="by-dropdown-title">
            {{
              pagination[i.prop]
                ? i.data.find((j) => j.value === pagination[i.prop])
                  ? i.data.find((j) => j.value === pagination[i.prop]).label
                  : i.label
                : i.labelCopy
            }}
            <!-- {{ i.label || i.labelCopy }} -->
            <i style="margin-left: 5px" class="iconfont icon-iconm_xialan1"></i>
          </div>
          <ul class="by-dropdown-lists">
            <li
              @click="searchItemSelct('all', i, index)"
              v-if="i.isShowAll === false ? i.isShowAll : true"
              style=""
            >
              {{ $t("common.all") }}
            </li>
            <li
              v-for="j in i.data"
              :key="j.value"
              @click="searchItemSelct(j, i)"
              style=""
            >
              {{ j.label }}
            </li>
          </ul>
        </div>
      </div>

      <div style="display: flex">
        <el-input
          :placeholder="$t('common.pleaseEnterKeywords')"
          suffix-icon="search"
          size="mini"
          v-model="pagination.keyword"
          @keyup.enter="searchFn"
        >
        </el-input>
        <el-button
          type="primary"
          style="margin-left: 10px"
          size="default"
          v-no-double-click="searchFn"
          >{{ $t("common.search") }}</el-button
        >
        <div
          class="more-icon"
          @click="retrievalModalFn"
          v-if="$attrs.onMoreSearch"
        >
          <i class="iconfont icon-iconx_saixuan"></i>
        </div>
      </div>
    </div>
    <component :is="containerTag">
      <div class="filter-form-container">
        <slot />
      </div>

      <el-table
        ref="hocElTable"
        id="example"
        :data="source"
        v-if="!hideTable"
        style="width: 100%"
        v-bind="$attrs"
        v-on="tableEvents"
        row-key="id"
        lazy
        :load="load"
        :tree-props="{
          children: 'children',
          hasChildren: 'hasChildren',
        }"
        :height="tableHeight"
      >
        <el-table-column
          v-for="(item, index) in config"
          :key="index"
          v-bind="getAttrsValue(item)"
          :type="item.type || ''"
          :selectable="
            (rowData, rowIndex) => isSelectable(rowData, rowIndex, item)
          "
        >
          <template #default="scope" v-if="!item.type">
            <slot
              :name="item.attrs.slot"
              :item="scope.row"
              v-if="item.attrs.slot"
            >
              插槽占位符
            </slot>
            <div v-else-if="isFunction(getValue(scope, item))">
              <component
                :is="renderTypeList[getMatchRenderFunction(item)].target"
                :cell-list="getValue(scope, item)()"
                :row="scope.row"
                :parent="getParent"
                @click="
                  ($event) => {
                    handleNativeClick(getAttrsValue(item), $event, item);
                  }
                "
              />
            </div>
            <div v-else>
              {{ getValue(scope, item) }}
            </div>
          </template>
        </el-table-column>
      </el-table>

      <el-row
        v-if="!hidePagination"
        class="table-pagination"
        justify="end"
        type="flex"
      >
        <el-pagination
          background
          layout="total, sizes, prev, pager, next, jumper"
          :current-page="getPagination.pageNum"
          :page-size="getPagination.pageSize"
          :total="getPagination.total"
          @size-change="handleSizeChange"
          @current-change="handlePageChange"
        />
      </el-row>
    </component>
  </div>
</template>
  
  <script>
import { isFunction as isFn, isBoolean } from "./type";
import ElementsMapping from "./ElementsMapping";
import ComponentsMapping from "./ComponentsMapping";
import { computed, defineComponent, getCurrentInstance, ref, watch } from "vue";
import expand from "./expand";
import Sortable from "sortablejs";
export default defineComponent({
  name: "Table",
  components: {
    ElementsMapping,
    ComponentsMapping,
  },

  props: {
    hideSearch: {
      type: Boolean,
      default: false,
    },
    hideTable: {
      type: Boolean,
      default: false,
    },
    //顶部搜索下拉配置
    selectConfig: {
      type: Array,
      default() {
        return [];
      },
    },
    // 获取表格元数据时携带的参数
    filterParams: {
      type: Object,
      default() {
        return {};
      },
    },
    // 表格加载 loading
    loading: {
      type: Boolean,
      default: false,
    },
    // 表格名称
    title: {
      type: String,
      default: "",
    },
    // 表格元数据
    source: {
      type: Array,
      required: true,
      default() {
        return [];
      },
    },
    tableHeight: {
      type: Number,
      required: false,
    },
    searchConfig: {
      type: Object,
      default() {
        return {
          keyword: "",
        };
      },
    },
    statConfig: {
      type: Array,
      default() {
        return [];
      },
    },
    // 指定外层容器的渲染组件
    containerTag: {
      type: String,
      default: "div",
    },
    // 是否隐藏表头
    hideHeader: {
      type: Boolean,
      default: false,
    },
    // 是否隐藏分页
    hidePagination: {
      type: Boolean,
      default: false,
    },
    // 分页配置
    pagination: {
      type: Object,
      default() {
        return {};
      },
    },
    // 表格配置文件
    config: {
      type: Array,
      default() {
        return [];
      },
    },
    // 表头右上方的按钮组
    actionList: {
      type: Array,
      default() {
        return [{ text: "", action: () => {} }];
      },
    },
    // element table 原生事件
    tableEvents: {
      type: Object,
      default() {
        return {};
      },
    },
    searchKey: {
      type: String,
      default: "keyword",
    },
    // 是否显示过滤的全部选项
    // isShowAll: {
    //   type: Boolean,
    //   default: true,
    // },
  },

  setup(props) {
    const { proxy } = getCurrentInstance();
    const selectConfigCopy = computed(() => {
      return props.selectConfig.map((item) => {
        if (!item.labelCopy) item.labelCopy = { ...item }.label;
        return item;
      });
    });
    let isMore = ref(false);
    const changeStatData = () => {
      statWarpHeight.value = document.getElementById("statWarp").offsetHeight;
    };
    
    let statWarpHeight = ref(0);
    watch(
      proxy.statConfig,
      (newValue, oldValue) => {
        setTimeout(() => {
          //获取statWarp的height
          statWarpHeight.value =
            document.getElementById("statWarp").offsetHeight;
        }, 500);
      }, 
      { immediate: true }
    );
    let statSelectVal = ref(0);
    const retrievalModal = ref(false);
    const getAttrsValue = (item) => {
      const { attrs } = item;
      const result = {
        ...attrs,
      };
      delete result.prop;
      return result;
    };
    const renderTypeList = ref({
      render: {},
      renderHTML: {
        target: "elements-mapping",
      },
      renderComponent: {
        target: "components-mapping",
      },
      renderMoreBtn: {
        target: "more-btn",
      },
    });
    const getParent = computed(() => {
      return proxy.$parent;
    });
    const getPagination = computed(() => {
      const params = {
        pageNum: 1,
        pageSize: 10,
        total: 0,
      };
      return Object.assign({}, params, props.pagination);
    });
    const getActionList = computed(() => {
      return props.actionList
        .slice()
        .reverse()
        .filter((it) => it.text);
    });
    const getValue = (scope, configItem) => {
      const prop = configItem.attrs.prop;
      const renderName = getMatchRenderFunction(configItem);
      const renderObj = renderTypeList.value[renderName];
      if (renderObj && isFunction(configItem[renderName])) {
        return renderObj.target
          ? getRenderValue(scope, configItem, {
              name: renderName,
              type: "bind",
            })
          : getRenderValue(scope, configItem);
      }
      return scope.row[prop];
    };
    const getRenderValue = (
      scope,
      item,
      fn = { name: "render", type: "call" }
    ) => {
      const prop = item.attrs.prop;
      const propValue = prop && scope.row[prop];
      scope.row.$index = scope.$index;
      const args = propValue !== undefined ? propValue : scope.row;

      return item[fn.name][fn.type](getParent.value, args);
    };
    // 匹配 render 开头的函数
    const getMatchRenderFunction = (obj) => {
      return Object.keys(obj).find((key) => {
        const matchRender = key.match(/^render.*/);
        return matchRender && matchRender[0];
      });
    };
    const isFunction = (fn) => {
      return isFn(fn);
    };
    const searchFn = (val) => {
      if(props.loading) return;
      proxy.$emit(
        "getList",
        Object.assign(props.filterParams, {
          [props.searchKey]: props.pagination.keyword,
        })
      );
    };
    const retrievalModalFn = () => {
      proxy.$emit("moreSearch", "");
      //获取父组件定义的moreSearch方法
    };
    const handlePageChange = (val) => {
      proxy.$emit(
        "getList",
        Object.assign(props.filterParams, { pageNum: val })
      );
    };
    const handleSizeChange = (val) => {
      proxy.$emit(
        "getList",
        Object.assign(props.filterParams, { pageSize: val })
      );
    };
    const getHeaderActions = (item) => {
      return {
        ...item.attrs,
      };
    };
    const stopBubbles = (e) => {
      const event = e || window.event;
      if (event && event.stopPropagation) {
        event.stopPropagation();
      } else {
        event.cancelBubble = true;
      }
    };
    const handleNativeClick = ({ isBubble }, e, item) => {
      // 考虑到单元格内渲染了组件，并且组件自身可能含有点击事件，故添加了阻止冒泡机制
      // 若指定 isBubble 为 false，则当前单元格恢复冒泡机制
      if (isBoolean(isBubble) && !isBubble) return;
      stopBubbles(e);
    };
    //下拉搜索相关

    const searchItemSelct = (item, i, index) => {
      if (item == "all") {
        i.label = { ...props.selectConfig[index] }.labelCopy;
        proxy.$emit(
          "getList",
          Object.assign(props.filterParams, { [i.prop]: "" })
        );
        return;
      }
      i.label = item.label;
      proxy.$emit(
        "getList",
        Object.assign(props.filterParams, { [i.prop]: item.value })
      );
    };

    const isSelectable = (row, index, item) => {
      if (item.type === "selection") {
        if (item.attrs && item.attrs.checkAtt) {
          if (row[item.attrs.checkAtt]) {
            return row[item.attrs.checkAtt];
          }
        } else {
          return true;
        }
      }
    };
    const hocElTable = ref();

    return {
      getParent,
      getPagination,
      renderTypeList,
      getActionList,
      getAttrsValue,
      getValue,
      getRenderValue,
      getMatchRenderFunction,
      isFunction,
      handlePageChange,
      handleSizeChange,
      getHeaderActions,
      stopBubbles,
      handleNativeClick,
      searchFn,
      searchItemSelct,
      selectConfigCopy,
      isSelectable,
      retrievalModal,
      retrievalModalFn,
      statSelectVal,
      statWarpHeight,
      isMore,
      changeStatData,
      hocElTable,
    };
  },
});
</script>
<style>
.table-list-container th {
  color: #333 !important;
}
.by-table td .el-button + .el-button {
  margin-left: 0 !important;
}
.by-table td .el-button {
  background: none !important;
  margin: 0 !important;
  padding: 8px 6px !important;
}
.el-checkbox__input.is-disabled .el-checkbox__inner {
  background-color: #dee1e6;
  border-color: #b2b4b9;
}
.el-table .cell {
  line-height: 34px;
}
</style>
<style lang="scss" scoped>
.sortableActive {
  background: #f5f7fa !important;
}
.show-more {
  height: auto !important;
}
.stat-warp {
  margin-bottom: 20px;
  background: #fff;
  padding: 0 20px;
  height: 200px;
  overflow: hidden;
  position: relative;
  .more-btn {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    height: 40px;
    cursor: pointer;
    font-size: 12px;
    line-height: 30px;
    text-align: center;
    background: linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.8) 100%);
    i{
      color:#999;
    }
  }
  .title {
    height: 60px;
    select {
      height: 60px;
      border: none;
      outline: none;
      -webkit-appearance: none;
      appearance: none;
      font-size: 14px;
      font-weight: bold;
      background: url("@/assets/images/sanjiao.png") no-repeat right center;
      padding-right: 20px;
    }
    div {
      height: 60px;
      font-size: 14px;
      font-weight: bold;
      line-height: 60px;
    }
  }
  ul {
    padding: 0;
    overflow: hidden;
    margin: 0;
    li {
      list-style: none;
      min-width: 285px;
      box-sizing: border-box;
      margin: 0 20px 20px 0;
      background: #eff6ff;
      float: left;
      overflow: hidden;
      padding: 20px;
      color: #333333;
      border-radius: 10px;
      .label {
        font-size: 14px;
      }
      .label::before {
        width: 10px;
        height: 10px;
        content: "";
        border-radius: 50%;
        background: #0084ff;
        display: inline-block;
        margin-right: 10px;
      }
      .num {
        margin-top: 10px;
        font-size: 24px;
        font-weight: bold;
      }
    }
    //#F5F3FF #9E64ED
    .theme2 {
      background: #f5f3ff;
      .label::before {
        background: #9e64ed;
      }
    }
    //#FFF1E1 #FF9315
    .theme3 {
      background: #fff1e1;
      .label::before {
        background: #ff9315;
      }
    }
    //#E2FBE8 #39C55A
    .theme4 {
      background: #e2fbe8;
      .label::before {
        background: #39c55a;
      }
    }
    .theme5 {
      background: #ffebe9;
      .label::before {
        background: #f94539;
      }
    }
    .theme6 {
      background: #e4f9f9;
      .label::before {
        background: #53cbcb;
      }
    }
    .multi-data {
      .label::before {
        display: none;
      }
      .label {
        font-size: 14px;
        font-weight: bold;
        color: #333;
        margin-bottom: 8px;
      }
      .num-warp {
        overflow: hidden;
        .num-box {
          float: left;
          min-width: 80px;
          margin-right: 20px;
          .num-small {
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 8px;
          }
          .label-small {
            color: #666;
            font-size: 14px;
          }
        }
      }
    }
  }
}
.by-search {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
  .more-icon {
    float: right;
    cursor: pointer;
    line-height: 32px;
    text-align: center;
    margin-left: 5px;
  }
}
.by-dropdown {
  position: relative;
  text-align: left;
  height: 32px;
  z-index: 1010;
  padding: 0 10px;
  transition: all 0.5s ease;
  cursor: pointer;
  line-height: 32px;

  .by-dropdown-title {
    font-size: 14px;
    background-color: #fff;
  }
  ul {
    position: absolute;
    left: 0;
    top: 32px;
    padding: 0;
    margin: 0;
    z-index: 100;
    display: none;
    white-space: nowrap;
    min-width: 100%;
    li {
      list-style: none;
      font-size: 12px;
      height: 30px;
      padding: 0 10px;
      text-align: left;
      line-height: 30px;
    }
    li:hover {
      background-color: #eff6ff;
      color: #0084ff;
    }
  }
}

.by-dropdown::before {
  display: block;
  width: 1px;
  content: " ";
  position: absolute;
  height: 14px;
  top: 8px;
  background-color: #ddd;
  right: 0;
  z-index: 1011;
}

.by-dropdown:hover {
  background: #ffffff;

  border-radius: 2px 2px 2px 2px;
  opacity: 1;
  ul {
    background: #ffffff;
    box-shadow: 0px 2px 16px 1px rgba(0, 0, 0, 0.06);
    border-radius: 2px 2px 2px 2px;
    opacity: 1;
    display: block;
    text-align: left;
  }
}
.header-actions {
  flex: 1;
  overflow-x: auto;
  padding: 20px;
  background: #fff;
  margin-bottom: 20px;
  .overflow-box {
    :deep() .el-button:nth-child(1) {
      margin-left: 10px;
    }
  }
}
.table-list-container {
  background: #fff;
  padding: 13px 20px 20px;
  .table-pagination {
    padding-top: 20px;
  }
  .header {
    display: flex;
    padding-bottom: 20px;
  }
  .el-table {
    :deep() th {
      font-size: 14px;
    }
    :deep() td {
      font-size: 14px;
    }
  }
}
.by-dropdown-lists {
  max-height: 50vh;
  overflow-y: auto;
  line-height: 1;
}
</style>