<template>
  <el-table
      ref="tableRef"
      :data="tableData"
      style="width: 100%"
      @selection-change="selectionChange"
      @row-click="rowClick"
      :height="props.finalHeight === null ? visibleWindowSize.height - props.height : props.finalHeight"
      highlight-current-row
      @row-contextmenu="contextmenu"
      :row-key="props.rowKey"
      border
      @select-all="selectAll"
      :default-expand-all="props.defaultExpandAll"
      stripe>
    <slot/>
  </el-table>
  <el-pagination
      v-if="props.openPaging"
      :current-page="pageObject.currentPage"
      :page-size="pageObject.pageSize"
      :total="pageObject.total"
      :layout="props.layout"
      :small="props.small"
      :page-sizes="props.pageSizes"
      @current-change="currentChange"
      @size-change="sizeChange"/>
</template>

<script setup name='XcTable'>
import {ElMessage} from "element-plus";
import {BizException, ExceptionEnum} from "@/utils/BizException";
import {getVisibleSize, visibleWindowSize} from "@/utils/window-size";
import {onClickOutside} from "@vueuse/core";

const props = defineProps({
  finalHeight: {
    type: Number,
    default: null
  },
  data: {
    type: Object,
    default: null
  },
  localData: {
    type: Array,
    default: null
  },
  rowKey: {
    type: String
  },
  height: {
    type: Number,
    default: 0
  },
  localPaging: {
    type: Boolean,
    default: false
  },
  openPaging: {
    type: Boolean,
    default: true
  },
  layout: {
    type: String,
    default: 'total, sizes, prev, pager, next, jumper'
  },
  small: {
    type: Boolean,
    default: false
  },
  pageSizes: {
    type: Array,
    default: [10, 20, 30, 100]
  },
  isArray: {
    type: Boolean,
    default: false
  },
  defaultExpandAll: {
    type: Boolean,
    default: true
  }
})
const emit = defineEmits([
  'currentChange',
  'sizeChange',
  'rowClick',
  'selectionChange',
  'rowContextmenu'
])

const tableRef = ref(null)
let selection = $ref([])

const tableData = computed(() => {
  if (!props.openPaging) {
    return pageObject.data
  }
  if (props.localPaging) {
    return props.data.data.slice((props.data.currentPage - 1) * props.data.pageSize, props.data.currentPage * props.data.pageSize)
  } else if (isLocalData) {
    return pageObject.data.slice((pageObject.currentPage - 1) * pageObject.pageSize, pageObject.currentPage * pageObject.pageSize)
  } else {
    return pageObject.data
  }
})

let flag = false // 默认 为全不选
const selectAll = (selection) => {
  flag = !flag
  if (!flag) {
    // 在点击了全不选中 需要清空
    tableRef.value.clearSelection()
    return
  }
  let length = selection.length
  for (let i = 0; i < length; i++) {
    let item = selection[i]
    if (item.children) {
      toggleSelection(item.children, flag)
    }
  }
}

const toggleSelection = (row, selected) => {
  if (row) {
    for (let i = 0, len = row.length; i < len; i++) {
      tableRef.value.toggleRowSelection(row[i], selected)
    }
  }
}

const selectionChange = (selection) => {
  emit('selectionChange', selection)
}

const tempRow = ref({})
const rowClick = (row, column, event) => {
  if (row.children) {
    for (let i = 0, len = row.children.length; i < len; i++) {
      tableRef.value.toggleRowSelection(row.children[i])
    }
  }
  tableRef.value.toggleRowSelection(row)
  emit('rowClick', row, column, event);
  if (tempRow.value) {
    // 防止多次点击触发事件
    if (tempRow.value === row) {
      return
    }
    tempRow.value['$show'] = false
  }
  row['$show'] = true
  tempRow.value = row
}

/**
 * 取消选择或者多选
 * @param val
 */
const toggleRowSelection = (...val) => {
  tableRef.value.toggleRowSelection(...val)
}

const currentChange = (val) => {
  if (isLocalData) {
    pageObject.currentPage = val
  } else {
    props.data.currentPage = val
    emit('currentChange', val)
    tableRef.value.setScrollTop(0)
  }
}

const sizeChange = (val) => {
  if (isLocalData) {
    pageObject.pageSize = val
  } else {
    props.data.pageSize = val
    props.data.currentPage = 1
    if (!props.localPaging) {
      props.data.total = 0
    }
    emit('sizeChange', val)
    tableRef.value.setScrollTop(0)
  }
}

const clearSelection = (msg = true) => {
  tableRef.value.clearSelection()
  if (msg) {
    ElMessage.success('清空成功。');
  }

}

const contextmenu = (row, column, event) => {
  event.returnValue = false
  event.preventDefault()
  emit('rowContextmenu', row)
}

/**
 * 获取选中的数据
 * @returns {*}
 */
const getSelectionRows = () => {
  let data = tableRef.value.getSelectionRows()
  if (data.length > 0) {
    return data;
  }
  BizException(ExceptionEnum.MESSAGE_ERROR, "请先选择数据")
}

let pageObject = $ref({
  currentPage: 1,
  pageSize: 30,
  total: 0,
  data: []
})

let isLocalData = $ref(false)

onMounted(() => {
  if (props.data !== null && props.localData !== null) {
    throw new Error('data 和 localData 不能同时使用')
  }
  if (props.localData !== null) {
    pageObject.data = props.localData
    pageObject.total = props.localData.length
    pageObject.currentPage = 1
    pageObject.pageSize = 30
    isLocalData = true
    watch(() => props.localData, () => {
      pageObject.data = props.localData
      pageObject.total = props.localData.length
    })
  } else {
    pageObject = props.data
  }
})

defineExpose({clearSelection, getSelectionRows, toggleRowSelection})

</script>

<style scoped>

</style>
