<script>
export default {
  name: "SuperTable",
  props: {
    value: {
      type: [Array],
      require: true,
    },
    dict: {
      type: [Object],
      require: true,
    },
    columns: {
      type: [Array],
      require: true,
    },
    stroage: {
      type: Boolean,
      default: false,
    },
    hideOperationColumns: {
      type: Boolean,
      default: false,
    },
  },
  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"),
    ElComputedInputV2: () => import("@/components/computed-input-v2/index.vue"),
  },
  data() {
    const { columns, stroage } = this.$props;
    const stroageKey = (
      this.$parent.$parent.$options.name + "_table"
    ).toUpperCase();
    const loaclColumns = JSON.parse(localStorage.getItem(stroageKey));
    const innerColumns = stroage && !!loaclColumns ? loaclColumns : columns;
    return {
      drawer: false,
      visible: false,
      top: 0,
      left: 0,
      stroageKey: stroageKey,
      innerColumns: innerColumns,
      currentData: {},
    };
  },
  computed: {
    innerValue: {
      get() {
        return this.value;
      },
      set(value) {
        this.$emit("input", value);
      },
    },
    showColumns: {
      get() {
        const { stroage, hideOperationColumns } = this.$props;
        return stroage && hideOperationColumns
          ? this.innerColumns.filter(({ item }) => item.hidden)
          : this.innerColumns;
      },
    },
  },
  watch: {
    visible(value) {
      if (value) {
        document.body.addEventListener("click", this.hideContextmenu);
        document.body.addEventListener("keydown", this.hideContextmenu);
      } else {
        document.body.removeEventListener("click", this.hideContextmenu);
        document.body.removeEventListener("keydown", this.hideContextmenu);
      }
    },
  },
  methods: {
    setColumns() {
      const { stroageKey, innerColumns } = this;
      this.$nextTick(() => {
        this.$refs.superTable.doLayout();
        localStorage.setItem(stroageKey, JSON.stringify(innerColumns));
      });
    },
    resetColumns() {
      const { stroageKey, innerColumns } = this;
      this.innerColumns = innerColumns.map(({ item, attr }) => ({
        attr,
        item: { ...item, hidden: true, fixed: false },
      }));
      this.$nextTick(() => {
        this.$refs.superTable.doLayout();
        localStorage.removeItem(stroageKey);
      });
    },
    openContextmenu(row, column, event) {
      this.visible = true;
      this.currentData = { row, column };
      this.$nextTick(() => {
        // 鼠标坐标
        const { x, y } = event;
        // 侧边栏宽度
        const [{ clientWidth: sideWidth }] =
          document.getElementsByClassName("sidebar-container");
        // 导航栏宽度
        const { clientHeight: navHeight } =
          document.getElementsByClassName("main-container")[0].firstChild;
        // 菜单宽度
        const [{ clientWidth: contextmenuWidth }] =
          document.getElementsByClassName("el-super-table_contextmenu");
        // 最大Y轴偏差
        const maxLeft = this.$el.offsetWidth - contextmenuWidth;
        if (x > maxLeft) {
          this.left = maxLeft + 10;
        } else {
          this.left = x - sideWidth;
        }
        this.top = y - navHeight;
      });
    },
    hideContextmenu(event) {
      const { type } = event;
      if (type === "click") {
        this.visible = false;
      }
      if (type === "keydown") {
        const { keyCode } = event;
        if (keyCode === 27) this.visible = false;
      }
    },
  },
  created() {},
  mounted() {},
  destroyed() {},
};
</script>

<template>
  <div class="el-super-table" @contextmenu.prevent.stop>
    <el-table
      v-bind="$attrs"
      v-on="$listeners"
      :data="innerValue"
      border
      ref="superTable"
      @row-contextmenu="openContextmenu"
    >
      <slot></slot>
      <el-table-column
        v-for="({ item, attr }, index) in showColumns"
        :key="index"
        :prop="item.key"
        :label="item.title"
        :fixed="item.fixed"
        :width="item.width || 250"
        show-overflow-tooltip
      >
        <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-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"
              >
              </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>
    </el-table>
    <el-drawer :visible.sync="drawer" size="25%" title="操作列" append-to-body>
      <el-row :gutter="20" style="margin: 0">
        <el-draggable
          v-model="innerColumns"
          :group="{ item: 'key' }"
          @change="setColumns"
        >
          <el-col
            v-for="({ item }, index) in innerColumns"
            :key="index"
            :span="24"
            style="
              display: flex;
              justify-content: space-between;
              padding: 15px 20px;
            "
          >
            <span style="cursor: move">
              <i class="el-icon-rank"></i>
              {{ item.title }}
            </span>
            <div>
              <el-radio-group
                v-model="item.hidden"
                :size="$attrs.size"
                style="margin: 0 15px 0 0"
                @change="setColumns"
              >
                <el-radio-button :label="true">显</el-radio-button>
                <el-radio-button :label="false">隐</el-radio-button>
              </el-radio-group>
              <el-radio-group
                v-model="item.fixed"
                :size="$attrs.size"
                @change="setColumns"
              >
                <el-radio-button :label="false">不</el-radio-button>
                <el-radio-button label="left">左</el-radio-button>
                <el-radio-button label="right">右</el-radio-button>
              </el-radio-group>
            </div>
          </el-col>
        </el-draggable>
      </el-row>
    </el-drawer>
    <transition name="el-fade-in-linear">
      <ul
        v-show="visible"
        :style="{ left: left + 'px', top: top + 'px' }"
        class="el-super-table_contextmenu"
      >
        <li v-if="hideOperationColumns" @click="drawer = true">
          <i class="el-icon-setting"></i>
          <span>设置布局</span>
        </li>
        <li v-if="hideOperationColumns" @click="resetColumns">
          <i class="el-icon-refresh"></i>
          <span>重置布局</span>
        </li>
        <slot name="contextmenu" v-bind="currentData"> </slot>
      </ul>
    </transition>
  </div>
</template>

<style lang="scss">
.el-super-table .el-table {
  overflow: hidden;
  border-radius: 5px;
}
.el-super-table_contextmenu {
  margin: 0;
  background: #fff;
  z-index: 3000;
  position: absolute;
  list-style-type: none;
  padding: 5px 0;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 400;
  color: #333;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  li {
    margin: 0;
    padding: 7px 16px;
    cursor: pointer;
    &:hover {
      background: #ddd;
    }
    span {
      margin: 0 0 0 5px;
    }
  }
}
</style>
