<template>
  <view class="ml-load-more" :class="[className || '', {'not-data': showNotData}]">
    <view class="ml-load-more-content">
      <slot></slot>
    </view>
    <view v-if="showNotData && !loading" class="ml-load-more-empty">
      <slot name="empty">
        <ml-not-data :emptyUrl="emptyUrl" :emptyText="emptyText" :emptyHint="emptyHint"></ml-not-data>
        <view class="ml-load-more-empty-content">
          <slot name="emptycontent"></slot>
        </view>
      </slot>
    </view>
    <view v-else-if="showPage" class="ml-load-more-warpper">
      <view v-if="loading" class="ml-load-more-loading">
        <ml-icon name="loading" roll />
        <text class="ml-load-more-loading-text">正在加载中...</text>
      </view>
      <template v-else>
        <view v-if="loadStatus === 'more'" class="ml-load-more-status-more">上拉显示更多</view>
        <view v-if="loadStatus === 'noMore'" class="ml-load-more-status-no-more">没有更多数据了</view>
      </template>
    </view>
  </view>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import globalStore from '../../../config/store'
import XEUtils from 'xe-utils'

export default defineComponent({
  name: 'MlLoadMore',
  props: {
    modelValue: Array,
    autoload: Boolean,
    showPage: Boolean,
    pageProps: Object,
    requestMethod: Function,
    filterForm: Object,
    emptyConfig: Object,
    className: String
  },
  inject: {
    currVM: {
      from: '$pageVM',
      default: null
    }
  },
  data () {
    return {
      loading: false,
      pageVO: {
        pageSize: globalStore.loadMore?.pageSize || 30,
        currPage: 1,
        total: 0
      },
      emptyUrl: '',
      emptyText: '',
      emptyHint: ''
    }
  },
  computed: {
    loadStatus () {
      if (this.loading) {
        return 'loading'
      }
      return this.pageVO.pageSize * this.pageVO.currPage < Number(this.pageVO.total) ? 'more' : 'noMore'
    },
    showNotData () {
      return !this.modelValue || !this.modelValue.length
    },
    pagePropOpts () {
      return { ...globalStore.loadMore?.pageProp, ...this.pageProps }
    },
    hasFilters () {
      const fields = this.emptyOpts.fields || []
      for (const key in this.filterForm) {
        const itemValue = this.filterForm[key]
        if (fields.includes(key) && (XEUtils.isArray(itemValue) ? itemValue.length : itemValue)) {
          return true
        }
      }
      return false
    },
    emptyOpts () {
      return Object.assign({}, this.emptyConfig)
    }
  },
  created () {
    this.$nextTick(() => {
      if (this.autoload && this.requestMethod) {
        this.reload().then(() => {
          this.$emit('init')
        })
      } else {
        this.$emit('init')
      }
    })
  },
  methods: {
    getParams () {
      return this.showPage
        ? {
            pageObj: this.pageVO,
            pageData: {
              [this.pagePropOpts.currentPage || 'page']: this.pageVO.currPage,
              [this.pagePropOpts.pageSize || 'limit']: this.pageVO.pageSize
            },
            data: {
              [this.pagePropOpts.currentPage || 'page']: this.pageVO.currPage,
              [this.pagePropOpts.pageSize || 'limit']: this.pageVO.pageSize
            }
          }
        : {
            data: {}
          }
    },
    getList () {
      if (this.requestMethod) {
        this.loading = true
        return Promise.resolve(
          this.requestMethod.call(this.currVM, this.getParams())
        ).then(res => {
          let data = []
          if (XEUtils.isFunction(globalStore.loadMore?.resProps?.result)) {
            data = globalStore.loadMore?.resProps?.result({ response: res }) || []
          } else {
            data = Array.isArray(res) ? res : XEUtils.get(res, globalStore.loadMore?.resProps?.result || 'datas')
          }
          if (this.showPage) {
            if (XEUtils.isFunction(globalStore.loadMore?.resProps?.total)) {
              this.pageVO.total = XEUtils.toNumber(globalStore.loadMore?.resProps?.total({ response: res }))
            } else {
              this.pageVO.total = XEUtils.toNumber(XEUtils.get(res, globalStore.loadMore?.resProps?.total || 'total'))
            }
          }
          this.loading = false
          return data
        }).catch((e) => {
          console.error(e)
          console.error('请检查是否在容器组件 <PageLayout ...> 或 <ViewContainer ...> 下使用')
          this.loading = false
          return []
        })
      }
      return Promise.resolve([])
    },
    reload () {
      this.pageVO.currPage = 1
      return this.load()
    },
    async load () {
      // if (this.$loading) {
      //   this.$loading.show()
      // }
      try {
        const data = await this.getList()
        // if (this.$loading) {
        //   this.$loading.hide()
        // }
        uni.stopPullDownRefresh()
        this.$emit('update:modelValue', data)
        this.$emit('query', { value: data })
      } catch (e) {
        // if (this.$loading) {
        //   this.$loading.hide()
        // }
        uni.stopPullDownRefresh()
        console.error(e)
      }
      this.updateEmptyStatus()
      return new Promise(resolve => {
        setTimeout(resolve, 100)
      })
    },
    async loadMore () {
      if (this.showPage && !this.loading && this.loadStatus === 'more') {
        try {
          this.pageVO.currPage++
          const data = await this.getList()
          const moreList = (this.modelValue || []).concat(data)
          this.$emit('update:modelValue', moreList)
          this.$emit('more', { value: moreList })
        } catch (e) {
          console.error(e)
        }
      }
    },
    updateEmptyStatus () {
      this.$nextTick(() => {
        if (this.hasFilters) {
          this.emptyUrl = this.emptyOpts.resultUrl || globalStore.loadMore?.notData.resultUrl || ''
          this.emptyText = XEUtils.template(this.emptyOpts.resultText || globalStore.loadMore?.notData.resultText, this.filterForm) || ''
          this.emptyHint = XEUtils.template(this.emptyOpts.resultHint || globalStore.loadMore?.notData.resultHint, this.filterForm) || ''
        } else {
          this.emptyUrl = this.emptyOpts.emptyUrl || globalStore.loadMore?.notData.emptyUrl || ''
          this.emptyText = this.emptyOpts.emptyText || globalStore.loadMore?.notData.emptyText || ''
          this.emptyHint = this.emptyOpts.emptyHint || globalStore.loadMore?.notData.emptyHint || ''
        }
      })
    }
  }
})
</script>

<style lang="scss">
.ml-load-more {
  &.not-data {
    .ml-load-more-content {
      display: none;
    }
  }
  .ml-load-more-empty-content {
    text-align: center;
  }
}
.ml-load-more-warpper {
  text-align: center;
  padding-bottom: 20rpx;
  color: rgb(119, 119, 119);
  .ml-load-more-loading {
    padding: 20rpx;
    .ml-load-more-loading-text {
      padding-left: 10rpx;
    }
  }
  .ml-load-more-status-more,
  .ml-load-more-status-no-more {
    padding: 20rpx;
  }
}
</style>
