|
@@ -0,0 +1,183 @@
|
|
|
+<template>
|
|
|
+ <!-- 查询区域 -->
|
|
|
+ <uni-search-bar class="uni-mt-10" v-model="name" radius="100" v-if="hasSearcBar" :placeholder="placeholder"
|
|
|
+ :bgColor="searchBarColor" clearButton="auto" cancelButton="none" @confirm="onSearch" @blur="onSearch" />
|
|
|
+ <!-- tab选择区域 -->
|
|
|
+ <view class="lli-status-box" v-if="hasTab">
|
|
|
+ <text :class="['status-item', activeTab === item.value? 'click':'' ]" v-for="item in tabList" :key="item.value"
|
|
|
+ @click="onTavChange(item)">{{item.label}}</text>
|
|
|
+ </view>
|
|
|
+ <!-- 无限滚动区域 -->
|
|
|
+ <scroll-view class="scroll-container" :scroll-y="true" :refresher-enabled="true" :refresher-triggered="triggered"
|
|
|
+ :refresher-threshold="100" refresher-background="lightgreen" @refresherrefresh="onRefresh"
|
|
|
+ @scrolltolower="onReachBottom" @refresherrestore="onRestore">
|
|
|
+ <slot :list="list"></slot>
|
|
|
+ <view style="width: 100%;text-align: center;font-size: 14px;color:#ccc;" v-if="isComplete">没有更多啦~</view>
|
|
|
+ </scroll-view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+ import {
|
|
|
+ ref,
|
|
|
+ onMounted,
|
|
|
+ computed
|
|
|
+ } from "vue";
|
|
|
+
|
|
|
+ import {
|
|
|
+ onLoad
|
|
|
+ } from "@dcloudio/uni-app"
|
|
|
+
|
|
|
+ const props = defineProps({
|
|
|
+ refreshFn: {
|
|
|
+ type: Function,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ tabData: {
|
|
|
+ type: Object
|
|
|
+ },
|
|
|
+ size: {
|
|
|
+ type: Number,
|
|
|
+ default: 2
|
|
|
+ },
|
|
|
+ hasSearcBar: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
+ searchBarKey: {
|
|
|
+ type: String,
|
|
|
+ default: 'name'
|
|
|
+ },
|
|
|
+ hasTab: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
+ defaultTab: {
|
|
|
+ type: [String, Number]
|
|
|
+ },
|
|
|
+ tabList: {
|
|
|
+ type: Array,
|
|
|
+ default: () => [],
|
|
|
+ },
|
|
|
+ tabKey: {
|
|
|
+ type: String,
|
|
|
+ default: 'status'
|
|
|
+ },
|
|
|
+ placeholder: {
|
|
|
+ type: String,
|
|
|
+ default: '请输入考试名称'
|
|
|
+ },
|
|
|
+ searchBarColor: {
|
|
|
+ type: String,
|
|
|
+ default: "#F3F3F4"
|
|
|
+ },
|
|
|
+ tabData: {
|
|
|
+ type: Object,
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ const page = ref(1);
|
|
|
+ const list = ref([]); // 项目列表
|
|
|
+ const triggered = ref(false); // 是否触发下拉刷新
|
|
|
+ const freshing = ref(false); // 是否加载中
|
|
|
+ const total = ref(0); // 项目总数
|
|
|
+ const name = ref(''); // 查询名
|
|
|
+ const activeTab = ref(props.defaultTab);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否已完全加载
|
|
|
+ */
|
|
|
+ const isComplete = computed(() => {
|
|
|
+ if (total.value === 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return total.value === list.value.length
|
|
|
+ })
|
|
|
+
|
|
|
+ // 重置
|
|
|
+ function reset() {
|
|
|
+ list.value = [];
|
|
|
+ page.value = 1;
|
|
|
+ triggered.value = false;
|
|
|
+ freshing.value = false;
|
|
|
+ total.value = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 切换tab
|
|
|
+ function onTavChange(item) {
|
|
|
+ activeTab.value = item.value;
|
|
|
+ name.value = "";
|
|
|
+ reset();
|
|
|
+ getData("do-search");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询
|
|
|
+ function onSearch({
|
|
|
+ value
|
|
|
+ }) {
|
|
|
+ name.value = value;
|
|
|
+ reset();
|
|
|
+ getData("do-search");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取数据
|
|
|
+ function getData(action) {
|
|
|
+ const options = Object.assign({}, {
|
|
|
+ page: page.value,
|
|
|
+ size: props.size,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (props.hasTab) {
|
|
|
+ options[props.tabKey] = activeTab.value;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (props.hasSearcBar) {
|
|
|
+ options[props.searchBarKey] = name.value;
|
|
|
+ }
|
|
|
+ props.refreshFn(options).then(res => {
|
|
|
+ total.value = res.data.total;
|
|
|
+ action === "do-search" && (list.value = res.data.data); // 查询更新
|
|
|
+ action === "pull-down-refresh" && (list.value = res.data.data); // 下拉更新数据
|
|
|
+ action === "reach-buttom" && (list.value = [...list.value, ...res.data.data]); // 无限滚动更新数据
|
|
|
+ }).finally(() => {
|
|
|
+ triggered.value = false;
|
|
|
+ freshing.value = false;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ onLoad(() => {
|
|
|
+ freshing.value = false;
|
|
|
+ setTimeout(() => {
|
|
|
+ triggered.value = true
|
|
|
+ }, 50)
|
|
|
+ })
|
|
|
+
|
|
|
+ // 下拉刷新触发
|
|
|
+ function onRefresh() {
|
|
|
+ if (freshing.value) return;
|
|
|
+ freshing.value = true;
|
|
|
+ triggered.value = true;
|
|
|
+ page.value = 1;
|
|
|
+ getData('pull-down-refresh');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 下拉刷新复位
|
|
|
+ function onRestore() {
|
|
|
+ triggered.value = 'restore'; // 需要重置
|
|
|
+ }
|
|
|
+
|
|
|
+ // 无限滚动
|
|
|
+ function onReachBottom() {
|
|
|
+ if (freshing.value) return;
|
|
|
+ if (isComplete.value) return;
|
|
|
+ freshing.value = true;
|
|
|
+ page.value++;
|
|
|
+ getData('reach-buttom')
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+ .scroll-container {
|
|
|
+ height: calc(100vh - 220rpx)
|
|
|
+ }
|
|
|
+</style>
|