list.vue 4.28 KB
<template>
  <view :class="['list', name ? `list-${name}` : '']">
    <template v-if="list.length > 0">
      <slot>
        <template v-for="(item, index) in list">
          <slot name="item" :item="item" :index="index"></slot>
        </template>
      </slot>
      <slot name="loadmore">
        <u-loadmore :status="status" />
      </slot>
    </template>
    <template v-else>
      <view v-if="!loading">
        <view v-if="verify && !authed">
          <slot name="extra">
            <u-empty icon="https://download.shjiuze.cn/assets/image/empty/unlogin.png" text="您还未登录">
              <u-button shape="circle" type="primary" :custom-style="{ marginTop: '32rpx', width: '200rpx' }" @click="openLogin">立即登录</u-button>
            </u-empty>
          </slot>
        </view>
        <slot v-else name="empty">
          <u-empty icon="https://download.shjiuze.cn/assets/image/empty/list.png" text="暂无数据"></u-empty>
        </slot>
      </view>
    </template>
  </view>
</template>

<script>
import { mapState } from 'vuex';

export default {
  props: {
    name: String,
    value: {
      type: Array,
      default: () => [],
    },
    pageSize: {
      type: Number,
      default: 20,
    },
    api: {
      type: Function,
      default: () => {},
      required: true,
    },
    unauth: {
      type: Function,
      default: () => {},
      required: false,
    },
    verify: Boolean,
    addOption: Function,
  },
  data() {
    return {
      list: this.value,
      currentPage: 1,
      loading: false,
      finished: false,
      refreshing: false,
    }
  },
  computed: {
    ...mapState(['authed']),
    status() {
      if (this.loading) {
        return 'loading';
      }
      if (this.finished) {
        return 'nomore';
      }
      return 'loadmore';
    }
  },
  mounted() {
    if ((this.verify && this.authed) || !this.verify) {
      this.pullDownRefresh({ showLoading: true });
    }
    if (this.verify) {
      uni.$on('authed', authed => {
        if (authed) {
          this.pullDownRefresh({ showLoading: true });
        }
      });
    }
  },
  watch: {
    value(val) {
      this.list = val;
    },
    loading(val) {
      this.$emit('update:loading', val);
    }
  },
  methods: {
    openLogin() {
      uni.navigateTo({ url: '/pages/login/login' });
    },
    search(config) {
      this.pullDownRefresh(config);
    },
    loadData({ showLoading } = {}) {
      if (!((this.verify && this.authed) || !this.verify)) {
        this.list = [];
        // 预留未登录需刷新情况
        if(this.unauth){
          return this.unauth.call(this.$root).finally(()=>{
            uni.hideLoading();
            uni.stopPullDownRefresh();
          });
        }
        uni.hideLoading();
        uni.stopPullDownRefresh();
        return;
      }
      if (this.finished) {
        return;
      }
      if (!this.loading) {
        this.loading = true;
        let params = {
          currentPage: this.currentPage,
          pageSize: this.pageSize,
        };
        if (this.currentPage === 1 && showLoading) {
          uni.showLoading({ content: '加载中...' });
        }
        this.api.bind(this.$root)(params).then(response => {
          const { result = [], totalCount } = response;
          this.list = this.currentPage === 1 ? result : this.list.concat(result);
          if(this.addOption){
            this.addOption(this.list)
          }else{
            this.$emit('input', this.list);
          }
          if (this.list.length >= totalCount || (!totalCount && result.length === 0)) {
            this.finished = true;
          }
          this.currentPage += 1;
          this.refreshing = false;
          this.$nextTick(() => {
            this.loading = false;
          })
        }).catch((err) => {
          uni.showToast({ title: err});
          this.finished = true;
          this.currentPage = 1;
          this.refreshing = false;
          this.$nextTick(() => {
            this.loading = false;
          })
        }).finally(() => {
          uni.hideLoading();
          uni.stopPullDownRefresh();
        });
      }
    },
    pullDownRefresh(data) {
      this.finished = false;
      this.refreshing = true;
      this.currentPage = 1;
      this.loadData(data);
    },
    reachBottom() {
      this.loadData();
    },
  }
}
</script>