topfans/frontend/pages/starbook/items.vue
2026-04-17 17:17:32 +08:00

288 lines
6.0 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="page-container">
<Header :showBack="true" backIconColor="#e6e6e6" :title="pageTitle" />
<!-- 加载中 -->
<view v-if="loading && page === 1" class="loading-container">
<text class="loading-text">加载中...</text>
</view>
<!-- 空状态 -->
<view v-else-if="!hasData" class="empty-container">
<text class="empty-text">暂无藏品</text>
</view>
<!-- 藏品网格 -->
<view v-else class="nft-grid-container">
<view
v-for="item in items"
:key="item.asset_id"
class="nft-grid-item"
@click="handleCardClick(item)"
>
<NftCard
:cover-image="item.cover_url_signed"
:width="cardSize"
:height="cardSize"
:locked="false"
:custom-style="cardCustomStyle"
/>
<view class="nft-info">
<text class="nft-name">{{ item.name }}</text>
<text class="nft-likes">★{{ item.like_count }}</text>
</view>
</view>
</view>
<!-- 分页提示 -->
<view v-if="hasMore && !loading" class="load-more" @click="loadMore">
<text class="load-more-text">加载更多</text>
</view>
<!-- 加载中(加载更多) -->
<view v-if="loading && page > 1" class="loading-more">
<text class="loading-more-text">加载中...</text>
</view>
<!-- 没有更多了 -->
<view v-if="!hasMore && items.length > 0" class="no-more">
<text class="no-more-text"> 没有更多了 </text>
</view>
<BottomNav :activeTab="1" />
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import Header from "../components/Header.vue";
import BottomNav from "../components/BottomNav.vue";
import NftCard from "../components/NftCard.vue";
import { getStarbookItemsApi } from '@/utils/api.js';
// 屏幕宽度
const screenWidth = ref(0);
// 路由参数
const type = ref('regular');
const category = ref('castlove');
const grade = ref(null);
// 分页参数
const page = ref(1);
const pageSize = ref(20);
const total = ref(0);
// 藏品列表
const items = ref([]);
// 加载状态
const loading = ref(false);
// 计算卡片尺寸
const cardSize = computed(() => {
if (screenWidth.value === 0) return 200;
const rpxToPx = screenWidth.value / 750;
const padding = 30 * rpxToPx; // 左右各30rpx
const gap = 15 * rpxToPx; // 卡片间距15rpx3列有2个间距
const availableWidth = screenWidth.value - (padding * 2) - (gap * 2);
return Math.floor(availableWidth / 3);
});
// 卡片自定义样式
const cardCustomStyle = {
position: 'absolute',
top: '0',
left: '0'
};
// 页面标题
const pageTitle = computed(() => {
if (type.value === 'regular') {
return `普通 · ${formatGrade(grade.value)}`;
}
return category.value;
});
// 判断是否有数据
const hasData = computed(() => {
return items.value.length > 0;
});
// 判断是否有更多
const hasMore = computed(() => {
return items.value.length < total.value;
});
// grade 中文转换
const gradeMap = { 1: '一', 2: '二', 3: '三', 4: '四', 5: '五' };
function formatGrade(g) {
return `等级${gradeMap[g] || g}`;
}
// 加载数据
const loadData = async (append = false) => {
loading.value = true;
try {
const response = await getStarbookItemsApi(
type.value,
category.value,
grade.value,
page.value,
pageSize.value
);
if (response.code === 200 && response.data) {
if (append) {
items.value = [...items.value, ...(response.data.items || [])];
} else {
items.value = response.data.items || [];
}
total.value = response.data.total || 0;
}
} catch (error) {
console.error('获取藏品列表失败:', error);
uni.showToast({
title: error.message || '获取藏品列表失败',
icon: 'none',
duration: 2000
});
} finally {
loading.value = false;
}
};
// 加载更多
const loadMore = () => {
if (!hasMore.value || loading.value) return;
page.value++;
loadData(true);
};
// 点击卡片跳转到详情页
const handleCardClick = (item) => {
if (item.asset_id) {
uni.navigateTo({
url: `/pages/asset-detail/asset-detail?asset_id=${item.asset_id}`
});
}
};
// 监听页面滚动到底部
onMounted(() => {
const systemInfo = uni.getSystemInfoSync();
screenWidth.value = systemInfo.windowWidth;
// 获取路由参数
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const options = currentPage.options || currentPage.$page?.options || {};
type.value = options.type || 'regular';
category.value = options.category || 'castlove';
grade.value = options.grade ? parseInt(options.grade) : null;
page.value = parseInt(options.page) || 1;
// 加载数据
loadData();
});
// 触底加载更多
onReachBottom(() => {
if (hasMore.value && !loading.value) {
loadMore();
}
});
</script>
<style scoped>
.page-container {
position: relative;
width: 100vw;
min-height: 100vh;
overflow: hidden;
background: #0d0820;
}
.loading-container,
.empty-container {
display: flex;
justify-content: center;
align-items: center;
padding-top: 300rpx;
}
.loading-text,
.empty-text {
color: rgba(255, 255, 255, 0.6);
font-size: 28rpx;
}
/* 藏品网格容器 */
.nft-grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 15rpx;
row-gap: 20rpx;
padding: 250rpx 30rpx 180rpx;
width: 100%;
box-sizing: border-box;
}
.nft-grid-item {
position: relative;
width: 100%;
padding-top: 133.33%;
}
.nft-grid-item:active {
transform: scale(0.98);
}
/* 藏品信息 */
.nft-info {
padding: 10rpx 0;
text-align: center;
}
.nft-name {
display: block;
font-size: 22rpx;
color: rgba(255, 255, 255, 0.9);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.nft-likes {
font-size: 20rpx;
color: rgba(255, 255, 255, 0.5);
}
/* 加载更多 */
.load-more {
display: flex;
justify-content: center;
align-items: center;
padding: 30rpx;
}
.load-more-text {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.6);
}
.loading-more,
.no-more {
display: flex;
justify-content: center;
align-items: center;
padding: 30rpx;
}
.loading-more-text,
.no-more-text {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.4);
}
</style>