<script setup lang="ts">
import { Search, RefreshLeft } from '@element-plus/icons-vue'

interface IRemoteProps {
  params?: any
  httpRequest?: any
  beforeRequest?: any
  callback?: any
}

interface Props {
  remote?: IRemoteProps
  filters?: any[]
  filterForm?: any
  columns?: any[]
  data?: any[]
  hasPagination?: boolean
  limit?: number
  hasLoading?: boolean
}
const props = withDefaults(defineProps<Props>(), {
  hasPagination: true,
  hasLoading: true,
  limit: 10,
  filters: () => [],
  columns: () => [],
  data: () => [],
})

const filterFormRef = ref()
const loading = ref(false)
const tableRef = ref()
const dataList = ref<any[]>([])
const page = reactive({ total: 0, size: props.limit, currentPage: 1 })

const params = reactive({ ...props.remote?.params })
watchEffect(() => {
  Object.assign(params, props.remote?.params)
})
watchEffect(() => {
  dataList.value = props.data || []
})

// 获取数据
const fetchList = (isReset = false) => {
  /**
   * @param function httpRequest api接口
   * @param function beforeRequest 接口请求之前
   * @param function callback 接口请求成功回调
   */
  const { httpRequest, beforeRequest, callback } = props.remote || {}
  if (!httpRequest) {
    return
  }
  // 参数设置
  let requestParams = { ...params }
  // 翻页参数设置
  if (props.hasPagination) {
    requestParams.page = page.currentPage
    requestParams['per-page'] = page.size
  }
  // 接口请求之前
  if (beforeRequest) {
    requestParams = beforeRequest(requestParams, isReset)
  }
  for (const key in params) {
    if (params[key] === '' || params[key] === undefined || params[key] === undefined) {
      delete params[key]
    }
  }
  loading.value = true
  return (
    httpRequest(requestParams)
      .then((res: any) => {
        const { list = [], total = 0 } = callback ? callback(res.data, requestParams) : res.data || {}
        page.total = parseInt(total)
        dataList.value = list
      })
      // .catch(() => {
      //   page.total = 0
      //   dataList.value = []
      // })
      .finally(() => {
        loading.value = false
      })
  )
}

// 搜索
const search = () => {
  page.currentPage = 1
  return fetchList()
}

// 重置
const reset = () => {
  // 清空筛选条件
  filterFormRef.value?.resetFields()
  // 初始化页码
  page.currentPage = 1
  // 刷新列表
  return fetchList(true)
}

// 刷新
const refetch = (isForce = false) => {
  return isForce ? reset() : fetchList()
}

// 页数改变
const pageSizeChange = (value: number) => {
  page.currentPage = 1
  page.size = value
  fetchList()
}

onMounted(() => {
  fetchList()
})

defineExpose({ refetch, tableRef })
</script>

<template>
  <div class="table-list">
    <div class="table-list-hd">
      <!-- 筛选 -->
      <div class="table-list-filter" v-if="filters && filters.length">
        <el-form :inline="true" :model="params" v-bind="filterForm" ref="filterFormRef" @submit.prevent>
          <template v-for="item in filters" :key="item.prop">
            <el-form-item :label="item.label" :prop="item.prop">
              <template v-if="item.slots">
                <slot :name="item.slots" v-bind="{ params }"></slot>
              </template>
              <template v-else>
                <!-- input -->
                <el-input
                  v-model="params[item.prop]"
                  v-bind="item"
                  clearable
                  @change="search"
                  v-if="item.type === 'input'" />
                <!-- select -->
                <el-select
                  v-model="params[item.prop]"
                  v-bind="item"
                  filterable
                  clearable
                  @change="search"
                  v-if="item.type === 'select'">
                  <el-option
                    v-for="(option, index) in item.options"
                    :label="option[item.labelKey] || option.label || option"
                    :value="option[item.valueKey] || option.value || option"
                    :key="index" />
                </el-select>
              </template>
            </el-form-item>
          </template>
          <el-form-item class="filter-buttons">
            <el-button type="primary" :icon="Search" @click="search">搜索</el-button>
            <el-button :icon="RefreshLeft" @click="reset">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
      <!-- <div class="table-list-hd-aside"><slot name="header-aside" /></div> -->
    </div>
    <div class="table-list-buttons"><slot name="header-buttons"></slot></div>
    <slot></slot>
    <!-- 主体 -->
    <div class="table-list-bd">
      <slot name="body" v-bind="{ data: dataList }">
        <el-table
          :header-cell-style="{ background: '#ededed' }"
          :data="dataList"
          v-loading="loading && hasLoading"
          v-bind="$attrs"
          ref="tableRef">
          <el-table-column align="center" v-bind="item || {}" v-for="item in columns" :key="item.prop">
            <template #default="scope" v-if="item.slots || item.computed">
              <slot :name="item.slots" v-bind="scope" v-if="item.slots"></slot>
              <div v-html="item.computed(scope)" v-if="item.computed"></div>
            </template>
          </el-table-column>
        </el-table>
      </slot>
    </div>
    <!-- 底部 -->
    <div class="table-list-ft">
      <div>
        <slot name="footer"></slot>
      </div>
      <el-pagination
        class="table-list-pagination"
        background
        layout="total, sizes, prev, pager, next, jumper"
        :page-sizes="[10, 20, 30, 50]"
        :page-size="page.size"
        :total="page.total"
        v-model:currentPage="page.currentPage"
        @size-change="pageSizeChange"
        @current-change="fetchList()"
        :hide-on-single-page="true"
        v-if="hasPagination">
      </el-pagination>
    </div>
  </div>
</template>

<style lang="scss">
.table-list-hd {
  display: flex;
  margin-bottom: 20px;
  &:empty {
    display: none;
  }
}
.table-list-filter {
  flex: 1;
}
.table-list-buttons {
  margin-bottom: 20px;
  &:empty {
    display: none;
  }
}

.table-list-ft {
  padding: 10px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.table-list-pagination {
  text-align: right;
}
.el-table-column--selection .cell {
  padding: 0 14px !important;
}
.table-list-bd {
  .el-button {
    a {
      margin: -8px -15px;
      padding: 8px 15px;
    }
    &.is-text {
      padding: 8px;
    }
    &.is-text + .is-text {
      margin-left: 0;
    }
    &.is-plain {
      --el-button-border-color: var(--el-button-bg-color);
    }
  }
}
</style>
