| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- <template>
- <view class="page">
- <NavBar title="推荐记录" :showBack="true" />
- <scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
- <view class="card-set">
- <view class="card" v-for="item in list" :key="item.id">
- <view class="card-head">
- <view class="card-left">
- <text class="card-name">{{ item.inviteeName || '用户' + item.inviteeId }}</text>
- <text class="card-time">{{ item.createTime }}</text>
- </view>
- <view class="card-status" :class="statusClass(item.status)">
- <text>{{ item.status === 1 ? '已激活' : item.status === 2 ? '已奖励' : '待激活' }}</text>
- </view>
- </view>
- </view>
- </view>
- <view class="load-tip" v-if="loading"><view class="dot-row"><view class="pulse-dot"></view><view class="pulse-dot"></view><view class="pulse-dot"></view></view></view>
- <view class="end-tip" v-if="!hasMore && list.length > 0"><text>没有更多了</text></view>
- <view class="empty-state" v-if="!loading && list.length === 0"><text class="empty-text">暂无推荐记录</text></view>
- </scroll-view>
- </view>
- </template>
- <script setup lang="ts">
- import { ref, onMounted } from 'vue';
- import NavBar from '@/components/NavBar.vue';
- import { get } from '@/utils/request';
- import { DEFAULT_PAGE_SIZE } from '@/utils/constants';
- const list = ref<any[]>([]); const loading = ref(false); const hasMore = ref(true); const page = ref(1);
- const statusClass = (s: number) => s === 2 ? 'done' : s === 1 ? 'active' : 'pending';
- const loadData = async () => {
- loading.value = true;
- try { const res = await get('/distribution/referral/list', { page: page.value, pageSize: DEFAULT_PAGE_SIZE }); if (page.value === 1) list.value = res.list || []; else list.value = [...list.value, ...(res.list || [])]; hasMore.value = list.value.length < (res.total || 0); } catch { }
- loading.value = false;
- };
- const loadMore = () => { if (loading.value || !hasMore.value) return; page.value++; loadData(); };
- onMounted(() => loadData());
- </script>
- <style lang="scss" scoped>
- .page { height: 100vh; background: $bg-color-page; display: flex; flex-direction: column; padding-bottom: env(safe-area-inset-bottom); }
- .list-scroll { flex: 1; height: 0; }
- .card-set { padding: 20rpx 24rpx; display: flex; flex-direction: column; gap: 16rpx; }
- .card { background: $bg-color-card; border-radius: $radius-md; padding: 24rpx; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.05); }
- .card-head { display: flex; justify-content: space-between; align-items: center; }
- .card-left { flex: 1; }
- .card-name { font-size: 30rpx; font-weight: 600; color: $text-color-primary; display: block; margin-bottom: 6rpx; }
- .card-time { font-size: 24rpx; color: $text-color-muted; }
- .card-status { padding: 4rpx 14rpx; border-radius: 8rpx; font-size: 22rpx; font-weight: 500; }
- .card-status.done { background: $success-color-bg; color: $success-color; }
- .card-status.active { background: $info-color-bg; color: $info-color; }
- .card-status.pending { background: $warning-color-bg; color: $warning-color; }
- .load-tip { display: flex; justify-content: center; padding: 36rpx 0; }
- .dot-row { display: flex; gap: 8rpx; }
- .pulse-dot { width: 9rpx; height: 9rpx; background: $text-color-placeholder; border-radius: 50%; animation: pulse 1.2s ease-in-out infinite; }
- .pulse-dot:nth-child(2) { animation-delay: 0.2s; } .pulse-dot:nth-child(3) { animation-delay: 0.4s; }
- @keyframes pulse { 0%,80%,100% { transform: scale(0.5); opacity: 0.4; } 40% { transform: scale(1); opacity: 1; } }
- .end-tip { text-align: center; padding: 36rpx; font-size: 24rpx; color: $text-color-muted; }
- .empty-state { display: flex; align-items: center; justify-content: center; padding: 100rpx 0; }
- .empty-text { font-size: 28rpx; color: $text-color-muted; }
- </style>
|