<template>
  <div class="ui-load-more" :class="{'is-empty': isEmpty}" @scroll="handleScroll">
    <template v-if="!isEmpty">
      <slot name="data" :data="data">
        <div
          v-for="(item, index) in data"
          :key="index"
          class="ui-load-more__item"
        >
          <slot name="item" :index="index" :item="item"></slot>
        </div>
      </slot>
      <span class="ui-load-more__loading" v-if="loading">
        <span class="ui-load-more__loading-icon">
          <ui-loading :visible="loading" size="mini"></ui-loading>
        </span>
        <span class="ui-load-more__loading-text">数据加载中...</span>
      </span>
      <span class="ui-load-more__loaded" v-else-if="loaded">
        数据已加载完毕
      </span>
      <span class="ui-load-more__loadmore" v-else @click="handleLoadMoreClick">
        点击加载更多数据
      </span>
    </template>
    <template v-else>
      <div class="ui-load-more__refreshing" v-if="refreshing">
        <slot name="refreshing">数据加载中...</slot>
      </div>
      <div class="ui-load-more__empty" v-else>
        <slot name="empty">暂无数据</slot>
      </div>
    </template>
  </div>
</template>
<script>
import UiLoading from '@huntianning/components/packages/loading'

export default {
  name: 'UiLoadMore',
  components: {
    UiLoading
  },
  props: {
    pageSize: {
      type: Number,
      default: 20
    },
    /**
     * 查询数据方法
    */
    queryMethod: {
      type: Function
    },
    /**
     * 合并数据方法
    */
    mergeDataMethod: {
      type: Function
    },
    /**
     * 检查数据是否加载完毕
    */
    checkCompleteMethod: {
      type: Function
    }
  },
  data() {
    return {
      data: [],
      refreshing: false,
      loading: false,
      loaded: false,
      pageIndex: 0
    }
  },
  computed: {
    isEmpty() {
      return !this.data || !this.data.length
    }
  },
  created() {
    this.reload()
  },
  methods: {
    handleScroll() {
      if (this.loading || this.loaded) {
        return
      }
      if (this.$el.scrollTop >= this.$el.scrollHeight - this.$el.clientHeight) {
        this.pageIndex++
        this.loadData()
      }
    },
    handleRefreshClick() {
      return this.reload()
    },
    handleLoadMoreClick() {
      if (this.loading || this.loaded) {
        return
      }
      this.pageIndex++
      this.loadData()
    },
    reload() {
      this.data = []
      this.pageIndex = 0
      this.refreshing = true
      this.loaded = false
      return this.loadData().finally(() => {
        this.refreshing = false
      })
    },
    loadData() {
      if (!this.queryMethod) {
        return Promise.reject()
      }
      this.loading = true
      return this.queryMethod({
        pageIndex: this.pageIndex,
        pageSize: this.pageSize
      }).then((results) => {
        if (this.mergeDataMethod) {
          this.data = this.mergeDataMethod({
            newData: results,
            oldData: this.data
          })
        } else {
          this.data = [].concat(this.data, results)
        }
        if (this.checkCompleteMethod) {
          this.loaded = this.checkCompleteMethod({
            pageSize: this.pageSize,
            pageIndex: this.pageIndex,
            data: this.data
          })
        } else {
          if (results.length < this.pageSize) {
            this.loaded = true
          }
        }
      }).finally(() => {
        this.loading = false
      })
    }
  }
}
</script>
<style lang="less">
.ui-load-more{
  height: 100%;
  overflow-y: auto;
  position: relative;
  &.is-empty {
    .ui-load-more__loading{
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
  }
}
.ui-load-more__loaded,
.ui-load-more__loadmore,
.ui-load-more__loading{
  text-align: center;
  padding: 10px;
  color: #888;
  display: block;
  white-space: nowrap;
  background-color: #fff;
}
.ui-load-more__loadmore{
  cursor: pointer;
  &:hover {
    color: #007BFF;
  }
}
.ui-load-more__loading{
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
}
.ui-load-more__loading-icon {
  margin-right: 6px;
}
</style>
