<script>
export default {
  name: "SuperTable",
  props: {
    // 数据
    value: {
      type: [Array],
      require: true,
    },
    // 字典
    dict: {
      type: [Object],
      require: true,
    },
    // 分页
    page: {
      type: [Object],
      require: false,
    },
    // 模板
    columns: {
      type: [Array],
      require: true,
    },
    // 是否显示序号
    index: {
      type: Boolean,
      default: false,
    },
    // 是否显示单选
    radio: {
      type: Boolean,
      default: false,
    },
    // 是否显示多选
    checkbox: {
      type: Boolean,
      default: false,
    },
    // 是否显示分页
    pagination: {
      type: Boolean,
      default: false,
    },
    // 是否列操作
    convenitentOperation: {
      type: Boolean,
      default: false,
    },
    // 是否禁止选择
    selectable: {
      type: Function,
      default: () => {},
    },
  },
  components: {
    ElDictTag: () => import("@/components/DictTag/index.vue"),
    ElDraggable: () => import("@/components/draggable/index.vue"),
    ElFilePreview: () => import("@/components/file-preview/index.vue"),
    ElComputedInput: () => import("@/components/computed-input/index.vue"),
    ElPopoverSelectV2: () => import("@/components/popover-select-v2/index.vue"),
    ElPopoverMultipleSelectV2: () =>
      import("@/components/popover-select-v2/multiple.vue"),
    ElComputedInputV2: () => import("@/components/computed-input-v2/index.vue"),
    ElPopoverTreeSelect: () =>
      import("@/components/popover-tree-select/index.vue"),
    ButtonHide: () => import("./hide.vue"),
    ButtonFreeze: () => import("./freeze.vue"),
    IconHide: () => import("./once/hide.vue"),
    IconSort: () => import("./once/sort.vue"),
    IconFreeze: () => import("./once/freeze.vue"),
    IconFilter: () => import("./once/filters.vue"),
  },
  data() {
    const { columns } = this.$props;
    const innerColumns = columns.map(({ item, attr }) => ({
      attr,
      item: { hidden: true, ...item },
    }));
    return {
      innerColumns: innerColumns,
      rowKey: "id",
      // 选择
      selectData: [],
      selectState: false,
      // 过滤
      filterData: [],
      filterState: false,
    };
  },
  computed: {
    innerValue: {
      get() {
        if (this.filterState) {
          return this.filterData;
        } else if (this.selectState) {
          return this.selectData;
        } else {
          return this.$props.value;
        }
      },
      set(value) {
        this.$emit("input", value);
      },
    },
    showColumns: {
      get() {
        return this.innerColumns.filter(({ item }) => item.hidden);
      },
      set() {},
    },
    filterRules: {
      get() {
        return Object.fromEntries(
          this.innerColumns
            .filter(({ item }) => item.filter && !!item.filter.length)
            .map(({ item }) => [item.key, item.filter])
        );
      },
      set() {},
    },
  },
  watch: {
    filterRules: {
      handler: function (newValue) {
        function multiFilter(array, filters) {
          const filterKeys = Object.keys(filters);
          // filters all elements passing the criteria
          return array.filter((item) => {
            // dynamically validate all filter criteria
            return filterKeys.every((key) => {
              //ignore when the filter is empty Anne
              if (!filters[key].length) return true;
              return !!~filters[key].indexOf(item[key]);
            });
          });
        }
        this.filterState = JSON.stringify(newValue) !== "{}";
        this.filterData = multiFilter(this.$props.value, newValue);
      },
    },
  },
  methods: {
    //
    onSelectionChange(value) {
      this.selectData = value;
      this.$emit("row-select", this.selectData);
    },
    //
    onRowClick(row, column, event) {
      const { radio, checkbox } = this.$props;
      // 单选
      if (radio) {
        this.$emit("row-select", [row]);
      }
      // 多选
      if (checkbox) {
        this.$refs.superTable.toggleRowSelection(
          this.innerValue.find((item) => item.id === row.id)
        );
      }
    },
    // 冻结
    onHide(prop) {
      this.$nextTick(() => {
        this.$refs.superTable.doLayout();
      });
    },
    // 排序
    onSort(prop) {
      const { key, sort } = prop;
      this.$nextTick(() => {
        this.$refs.superTable.sort(key, sort);
        this.$refs.superTable.doLayout();
      });
    },
    // 冻结
    onFreeze() {
      this.$nextTick(() => {
        this.$refs.superTable.doLayout();
      });
    },
    // 过滤
    onFilter() {
      this.$nextTick(() => {
        this.$refs.superTable.doLayout();
      });
    },
    onFilters(value) {
      const {
        item: { key },
        attr: { dictName },
      } = value;
      let dataList = [];
      const dict = this.dict.type[dictName];
      dataList = Array.from(
        new Set(this.innerValue.map((item) => item[key]).filter((item) => item))
      ).map((item) => ({
        text: dictName
          ? (dict.find((dictItem) => dictItem.value == item) || {}).label
          : item,
        value: item,
      }));
      return dataList;
    },
    // 继承el-table的Method
    extendMethod() {
      const refMethod = Object.entries(this.$refs["superTable"]);
      for (const [key, value] of refMethod) {
        if (!(key.includes("$") || key.includes("_"))) {
          this[key] = value;
        }
      }
    },
  },
  created() {},
  mounted() {
    this.extendMethod();
  },
  destroyed() {},
};
</script>

<template>
  <div class="el-super-table">
    <el-table
      ref="superTable"
      border
      height="auto"
      :row-key="rowKey"
      :data="innerValue"
      :highlight-current-row="radio"
      @row-click="onRowClick"
      @selection-change="onSelectionChange"
      v-bind="$attrs"
      v-on="$listeners"
      style="flex: 1"
    >
      <!-- 多选 -->
      <el-table-column
        v-if="checkbox"
        :column-key="rowKey"
        fixed
        width="50"
        align="center"
        type="selection"
        reserve-selection
      >
      </el-table-column>
      <!-- 序号 -->
      <el-table-column
        v-if="index"
        :resizable="false"
        fixed
        width="50"
        label="序号"
        align="center"
        class="is-index"
      >
        <template slot-scope="scope">
          {{ scope.$index + 1 }}
        </template>
      </el-table-column>
      <el-table-column
        v-for="({ item, attr }, index) in showColumns"
        :key="item.key + index"
        :prop="item.key"
        :label="item.title"
        :fixed="item.fixed"
        :width="item.width || 200"
        show-overflow-tooltip
      >
        <template slot="header" slot-scope="scope">
          <template>
            <span v-if="item.require" style="color: #ff4949">*</span>
            <span
              :style="{
                color:
                  item.sort ||
                  item.fixed ||
                  (item.filter && !!item.filter.length)
                    ? '#1890ff'
                    : '',
              }"
            >
              {{ item.title }}
            </span>
            <template>
              <icon-sort
                v-if="item.sortabled"
                v-model="item.sort"
                @sort="onSort(item)"
              ></icon-sort>
              <icon-freeze
                v-if="item.fixedabled"
                v-model="item.fixed"
                @freeze="onFreeze"
              ></icon-freeze>
              <icon-filter
                v-if="item.filterabled"
                v-model="item.filter"
                :filters="onFilters({ item, attr })"
                @filter="onFilter"
              ></icon-filter>
              <icon-hide
                v-if="item.hiddenabled"
                v-model="item.hidden"
                @hide="onHide"
              ></icon-hide>
            </template>
          </template>
        </template>
        <template slot-scope="scope">
          <slot :name="item.key" v-bind="scope" :item="item" :attr="attr">
            <template v-if="attr.is">
              <component
                v-if="attr.is === 'el-dict-tag'"
                v-bind="attr"
                :size="$attrs.size"
                :value="scope.row[item.key]"
                :options="dict.type[attr.dictName]"
              ></component>
              <component
                v-else-if="attr.is === 'el-popover-select-v2'"
                v-bind="attr"
                v-model="scope.row[item.key]"
                :size="$attrs.size"
                :source.sync="scope.row"
              >
              </component>
              <component
                v-else-if="attr.is === 'el-popover-multiple-select-v2'"
                v-bind="attr"
                v-model="scope.row[item.key]"
                :size="$attrs.size"
                :source.sync="scope.row"
              >
              </component>
              <component
                v-else-if="attr.is === 'el-select'"
                v-bind="attr"
                v-model="scope.row[item.key]"
                :size="$attrs.size"
              >
                <template>
                  <el-option
                    v-for="item in dict.type[attr.dictName]"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  >
                  </el-option>
                </template>
              </component>
              <component
                v-else
                v-bind="attr"
                v-model="scope.row[item.key]"
                :size="$attrs.size"
                style="width: 100%"
              >
              </component
            ></template>
            <template v-else>
              <component v-if="attr.formatter" is="span">{{
                attr.formatter(scope.row)
              }}</component>
              <component v-else is="span">{{
                scope.row[item.key] || "--"
              }}</component>
            </template>
          </slot>
        </template>
      </el-table-column>
      <slot></slot>
    </el-table>
    <div
      style="
        height: 50px;
        display: flex;
        justify-content: space-between;
        align-items: center;
      "
    >
      <div class="mr-4">
        <template v-if="checkbox">
          <el-button
            v-if="selectState"
            size="mini"
            @click="selectState = !selectState"
          >
            所有列
          </el-button>
          <el-button
            v-else
            :disabled="!selectData.length"
            size="mini"
            @click="selectState = !selectState"
          >
            选择列
            {{ selectData.length ? ` ：${selectData.length}` : "" }}
          </el-button>
        </template>
        <template v-if="convenitentOperation">
          <button-hide v-model="innerColumns" @change="onHide"></button-hide>
          <!-- <button-freeze
            v-model="showColumns"
            @freeze="onFreeze"
          ></button-freeze> -->
        </template>
      </div>
      <pagination
        v-if="pagination"
        v-show="!selectState"
        :total="page.total"
        :page.sync="page.pageNum"
        :limit.sync="page.pageSize"
        @pagination="$emit('pagination', { ...$event })"
        style="height: 32px; padding: 0 !important; flex: 1; overflow-x: auto"
      />
    </div>
  </div>
</template>

<style lang="scss" scoped>
.el-super-table {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: auto;
}
::v-deep.el-super-table .el-table__header .cell {
  word-break: keep-all;
  white-space: nowrap;
  .icon-sort {
    display: none;
  }
  &:hover .icon-sort {
    display: inline-block;
  }
  .icon-freeze {
    display: none;
  }
  &:hover .icon-freeze {
    display: inline-block;
  }
  .icon-filter {
    display: none;
  }
  &:hover .icon-filter {
    display: inline-block;
  }
  .icon-hide {
    display: none;
  }
  &:hover .icon-hide {
    display: inline-block;
  }
}
</style>
