<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 || false"
        v-bind="getHeaderActions(item)"
        @click="item.action"
        :disabled="item.disabled || false"
      >
        {{ item.text }}
      </el-button>
    </div>
  </div>
  <div class="table-list-container by-table">
    <!-- 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 in selectConfigCopy"
          :key="i.prop"
          style="margin-right: 10px"
        >
          <div class="by-dropdown-title">
            {{ i.label }}<i class="el-icon-caret-bottom el-icon--right"></i>
          </div>
          <ul class="by-dropdown-lists">
            <li
              @click="searchItemSelct('all', i)"
              v-if="i.isShowAll === false ? i.isShowAll : true"
            >
              全部
            </li>
            <li
              v-for="j in i.data"
              :key="j.value"
              @click="searchItemSelct(j, i)"
            >
              {{ j.label }}
            </li>
          </ul>
        </div>
      </div>

      <div style="display: flex">
        <el-input
          placeholder="请输入关键字"
          suffix-icon="search"
          size="mini"
          v-model="keywrod"
          @keyup.enter="searchFn"
        >
        </el-input>
        <el-button
          type="primary"
          style="margin-left: 10px"
          size="default"
          @click="searchFn"
          >搜索</el-button
        >

        <div class="more-icon"><i class="el-icon-wind-power"></i></div>
        <div class="more-icon">
          <i class="el-icon-notebook-2"></i>
        </div>
      </div>
    </div>

    <component :is="containerTag">
      <div class="filter-form-container">
        <slot />
      </div>

      <el-table
        ref="hocElTable"
        v-loading="loading"
        :data="source"
        v-if="!hideTable"
        style="width: 100%"
        v-bind="$attrs"
        v-on="tableEvents"
        row-key="id"
        :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      >
        <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 } from "vue";
import expand from "./expand";
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 [];
      },
    },
    searchConfig: {
      type: Object,
      default() {
        return {
          keyword: "",
        };
      },
    },
    // 指定外层容器的渲染组件
    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 keywrod = ref("");
    const selectConfigCopy = computed(() => {
      return props.selectConfig.map((item) => {
        item.labelCopy = item.label;
        return item;
      });
    });
    console.log(selectConfigCopy);
    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",
      },
    });
    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) => {
      console.log(props);
      proxy.$emit(
        "getList",
        Object.assign(props.filterParams, { [props.searchKey]: keywrod.value })
      );
    };
    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) => {
      if (item == "all") {
        i.label = "全部";
        proxy.$emit(
          "getList",
          Object.assign(props.filterParams, { [i.prop]: "" })
        );
        return;
      }
      i.label = item.label;
      console.log(item, i);
      proxy.$emit(
        "getList",
        Object.assign(props.filterParams, { [i.prop]: item.value })
      );
    };

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

    return {
      getParent,
      getPagination,
      renderTypeList,
      getActionList,
      getAttrsValue,
      getValue,
      getRenderValue,
      getMatchRenderFunction,
      isFunction,
      handlePageChange,
      handleSizeChange,
      getHeaderActions,
      stopBubbles,
      handleNativeClick,
      keywrod,
      searchFn,
      searchItemSelct,
      selectConfigCopy,
      isSelectable,
    };
  },
});
</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;
}
</style>
  <style lang="scss" scoped>
.by-search {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
.by-dropdown {
  width: 106px;
  position: relative;
  text-align: left;
  height: 32px;
  z-index: 100;
  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;
    right: 0;
    top: 32px;
    padding: 0;
    margin: 0;
    z-index: 100;
    display: none;
    li {
      list-style: none;
      font-size: 12px;
      height: 30px;
      padding: 0 10px;
    }
    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: 101;
}

.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;
    }
  }
}
</style>