<template>
  <div class="header-actions" v-if="getActionList.length != 0 &&getActionList.length>2">
    <div class="overflow-box">
      <el-button v-for="(item, index) in getActionList" :key="index" :type="item.type || 'primary'" :plain="item.plain || false"
                 v-bind="getHeaderActions(item)" @click="item.action" :disabled="item.disabled || false">
        {{ item.text }}
      </el-button>
    </div>
  </div>
  <div class="stat-warp" v-if="statConfig.length != 0" :class="statWarpHeight > 200 && 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>
    <div class="more-btn" @click="isMore = !isMore" v-if="statWarpHeight > 200">
      <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="!hideAll">
    <!-- 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 v-if="getActionList.length != 0 &&getActionList.length <=2" style="margin-right:10px">
          <el-button v-for="(item, index) in getActionList" :key="index" :type="item.type || 'primary'" :plain="item.plain || false"
                     v-bind="getHeaderActions(item)" @click="item.action" :disabled="item.disabled || false">
            {{ item.text }}
          </el-button>
        </div>
        <div class="by-dropdown" v-for="(i, index) in selectConfigCopy" :key="i.prop" style="margin-right: 10px">
          <div v-if="i.type" class="selectTime" style="display:flex;align-items:center">
            <span style="font-size:14px;height:32px;margin-right:15px">{{i.label || ''}}</span>
            <el-date-picker v-model="pagination[i.prop]" type="date" size="small" :placeholder="i.placeholder" style="width:120px"
                            value-format="YYYY-MM-DD" @change="searchItemSelctOne(i,pagination[i.prop],pagination[i.propOne])" />
            <span style="margin-right:15px">-</span>
            <el-date-picker v-model="pagination[i.propOne]" type="date" size="small" :placeholder="i.placeholderOne" style="width:120px"
                            value-format="YYYY-MM-DD" @change="searchItemSelctOne(i,pagination[i.prop],pagination[i.propOne])" />
          </div>
          <div v-else>
            <div class="by-dropdown-title">
              <!-- {{i.label || i.labelCopy}} -->
              {{
              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 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 || j.dictKey" @click="searchItemSelct(j, i)" style="">
                {{ j.label || j.dictValue }}
              </li>
            </ul>
          </div>
        </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" @click="searchFn">{{ $t("common.search") }}</el-button>
        <div class="more-icon" @click="retrievalModalFn">
          <img src="@/assets/images/iconm_xiangyzk.png" alt="" />
        </div>
      </div>
    </div>
    <component :is="containerTag">
      <div class="filter-form-container">
        <slot />
      </div>

      <el-table ref="hocElTable" :data="source" v-if="!hideTable" style="width: 100%" v-bind="$attrs" v-on="tableEvents" row-key="id" :tree-props="{
          children: 'children',
          hasChildren: 'hasChildren',
        }" :height="tableHeight">
        <el-table-column v-for="(item, index) in configData" :key="index" v-bind="getAttrsValue(item)" :type="item.type || ''" :selectable="
            (rowData, rowIndex) => isSelectable(rowData, rowIndex, item)
          ">
          <template #header v-if="item.attrs.isNeedHeaderSlot">
            <slot :name="item.attrs.headerSlot" :headerLabel="item.attrs.label" v-if="item.attrs.headerSlot">
              头部插槽占位符
            </slot>
          </template>

          <template #default="scope" v-if="!item.type">
            <slot :name="item.attrs.slot" :item="scope.row" :headerLabel="item.attrs.label" 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,
    },
    onMoreSearch: {
      type: Boolean,
      default: true,
    },
    hideAll: {
      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 configData = ref([]);
    // configData.value = proxy.config.filter((x) => x && x.attrs);
    const configData = computed(() => proxy.config.filter((x) => x && x.attrs));
    // console.log(configData.value, "ssssssssss");
    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 = 0) => {
      if (item == "all") {
        i.label = { ...props.selectConfig[index] }.labelCopy;
        i.label = props.selectConfig[index].labelCopy;
        proxy.$emit(
          "getList",
          Object.assign(props.filterParams, { [i.prop]: "" })
        );
        return;
      }
      i.label = item.label || item.dictValue;
      proxy.$emit(
        "getList",
        Object.assign(props.filterParams, {
          [i.prop]: item.value || item.dictKey,
        })
      );
    };

    const searchItemSelctOne = (item, prop, propOne) => {
      if (prop && propOne) {
        proxy.$emit(
          "getList",
          Object.assign(props.filterParams, {
            [item.prop]: prop,
            [item.propOne]: propOne,
          })
        );
      } else if (prop == null && propOne == null) {
        proxy.$emit(
          "getList",
          Object.assign(props.filterParams, {
            [item.prop]: prop,
            [item.propOne]: propOne,
          })
        );
      }
    };

    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 {
      configData,
      getParent,
      getPagination,
      renderTypeList,
      getActionList,
      getAttrsValue,
      getValue,
      getRenderValue,
      getMatchRenderFunction,
      isFunction,
      handlePageChange,
      handleSizeChange,
      getHeaderActions,
      stopBubbles,
      handleNativeClick,
      searchFn,
      searchItemSelct,
      searchItemSelctOne,
      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: 80px;
    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: 15px;
  .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;
}
:deep(.selectTime .el-input__wrapper) {
  box-shadow: none;
}
:deep(.selectTime .el-input__inner) {
  color: #000 !important;
  font-size: 14px !important;
}
:deep(.selectTime .el-input .el-input__icon) {
  color: #000 !important;
  font-size: 14px !important;
}
</style>