2025-11-24 22:03:19 +08:00

294 lines
5.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="invite-page">
<view class="summary-card">
<view class="summary-item">
<text class="summary-value">{{ total }}</text>
<text class="summary-label">已邀请用户</text>
</view>
<view class="summary-divider"></view>
<view class="summary-item">
<text class="summary-value">{{ totalPoints }}</text>
<text class="summary-label">累计积分</text>
</view>
</view>
<scroll-view
class="invite-scroll"
scroll-y
@scrolltolower="loadMore"
:refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="refresh"
>
<view class="invite-list">
<view
class="invite-item"
v-for="user in inviteList"
:key="`${user.username}-${user.created_at}`"
>
<image class="avatar" :src="user.avatar_url || defaultAvatar" mode="aspectFill" />
<view class="invite-info">
<view class="invite-header">
<text class="invite-name">
{{ user.username || '未命名用户' }}
</text>
<text class="sex-tag" :class="getSexClass(user.sex)">
{{ getSexText(user.sex) }}
</text>
</view>
<text class="invite-time">邀请时间{{ formatDate(user.created_at) }}</text>
</view>
</view>
<view v-if="!loading && inviteList.length === 0" class="empty-state">
<text class="empty-icon">🤝</text>
<text class="empty-text">暂时还没有邀请记录</text>
</view>
<view v-if="loading && inviteList.length > 0" class="loading-more">
<text class="loading-text">加载中...</text>
</view>
<view v-if="!hasMore && inviteList.length > 0" class="no-more">
<text class="no-more-text">没有更多了</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import request from '@/api/request.js';
const INVITE_API_PATH = 'xcx/invite_users';
export default {
data() {
return {
inviteList: [],
page: 1,
pageSize: 10,
loading: false,
refreshing: false,
hasMore: true,
total: 0,
totalPoints: 0,
defaultAvatar: '/static/images/home/icon-1.png'
};
},
onLoad() {
this.loadInvitedUsers();
},
methods: {
formatDate(value) {
if (!value) return '--';
const date = new Date(value);
if (Number.isNaN(date.getTime())) return value;
const year = date.getFullYear();
const month = `${date.getMonth() + 1}`.padStart(2, '0');
const day = `${date.getDate()}`.padStart(2, '0');
const hour = `${date.getHours()}`.padStart(2, '0');
const minute = `${date.getMinutes()}`.padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}`;
},
getSexText(sex) {
const map = {
1: '男',
2: '女',
0: '保密'
};
return map.hasOwnProperty(sex) ? map[sex] : '保密';
},
getSexClass(sex) {
if (sex === 1) return 'tag-male';
if (sex === 2) return 'tag-female';
return 'tag-unknown';
},
async loadInvitedUsers() {
if (this.loading || !this.hasMore) return;
this.loading = true;
try {
const params = {
page: this.page,
page_size: this.pageSize
};
const response = await request(INVITE_API_PATH, 'GET', params);
const list = Array.isArray(response)
? response
: response?.list || response?.data || [];
this.total = response?.total ?? this.total ?? 0;
this.totalPoints = response?.total_points ?? response?.totalPoints ?? this.totalPoints;
if (this.page === 1) {
this.inviteList = list;
} else {
this.inviteList = [...this.inviteList, ...list];
}
const received = list.length;
if (received < this.pageSize) {
this.hasMore = false;
} else {
this.page += 1;
}
} catch (error) {
console.error('加载邀请列表失败', error);
if (this.page === 1) {
this.inviteList = [];
}
} finally {
this.loading = false;
this.refreshing = false;
}
},
refresh() {
this.refreshing = true;
this.page = 1;
this.hasMore = true;
this.inviteList = [];
this.loadInvitedUsers();
},
loadMore() {
if (!this.loading && this.hasMore) {
this.loadInvitedUsers();
}
}
}
};
</script>
<style scoped lang="scss">
.invite-page {
min-height: 100vh;
background-color: #f5f5f5;
padding: 24rpx;
display: flex;
flex-direction: column;
gap: 24rpx;
}
.summary-card {
background: linear-gradient(120deg, #f6f1ff 0%, #ffeef5 100%);
border-radius: 32rpx;
padding: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 16rpx 32rpx rgba(139, 64, 255, 0.12);
}
.summary-item {
display: flex;
flex-direction: column;
gap: 8rpx;
text-align: center;
flex: 1;
}
.summary-value {
font-size: 44rpx;
font-weight: 700;
color: #33195d;
}
.summary-label {
font-size: 26rpx;
color: #7b43ff;
}
.summary-divider {
width: 2rpx;
height: 80rpx;
background-color: rgba(255, 255, 255, 0.4);
}
.invite-scroll {
flex: 1;
height: calc(100vh - 240rpx);
}
.invite-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.invite-item {
background-color: #fff;
border-radius: 24rpx;
padding: 24rpx;
display: flex;
align-items: center;
gap: 24rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
}
.avatar {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
background-color: #f3f3f3;
}
.invite-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 12rpx;
}
.invite-header {
display: flex;
align-items: center;
gap: 16rpx;
}
.invite-name {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.sex-tag {
font-size: 24rpx;
padding: 6rpx 20rpx;
border-radius: 999rpx;
}
.tag-male {
background-color: #e3f2fd;
color: #1a73e8;
}
.tag-female {
background-color: #fde2ef;
color: #d81b60;
}
.tag-unknown {
background-color: #f1f3f4;
color: #5f6368;
}
.invite-time {
font-size: 26rpx;
color: #999;
}
.empty-state,
.loading-more,
.no-more {
text-align: center;
padding: 80rpx 0;
display: flex;
flex-direction: column;
gap: 16rpx;
color: #999;
}
.empty-icon {
font-size: 80rpx;
}
</style>