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

294 lines
6.2 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">
<image class="background-image" src="/static/background/starbook.jpg" mode="aspectFill"></image>
<Header :showGuideIcon="false" :showTaskIcon="false" :showStarActivityIcon="false" :showBack="true" backIconColor="#e6e6e6" />
<!-- 加载中 -->
<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)"
>
<image
class="nft-cover"
:src="item.coverUrl || item.cover_url_signed"
mode="aspectFill"
/>
<view class="nft-info">
<text class="nft-name">{{ item.name }}</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 v-if="showBottomNav" :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 { getStarbookItemsApi } from '@/utils/api.js';
import { getAssetCoverRealUrl } from '@/utils/assetImageHelper.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 showBottomNav = 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 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) {
const newItems = response.data.data.items || [];
// 转换封面 URL
for (const item of newItems) {
item.coverUrl = await getAssetCoverRealUrl(item.cover_url_signed || '');
}
if (append) {
items.value = [...items.value, ...newItems];
} else {
items.value = newItems;
}
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();
});
</script>
<style scoped>
.page-container {
position: relative;
width: 100vw;
min-height: 100vh;
overflow: hidden;
background: #0d0820;
}
.background-image {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 0;
pointer-events: none;
}
.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 {
position: relative;
z-index: 1;
display: flex;
flex-wrap: wrap;
padding: 250rpx 30rpx 100rpx;
width: 100%;
box-sizing: border-box;
}
.nft-grid-item {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 32rpx;
margin-left: 32rpx;
}
.nft-cover {
width: 192rpx;
height: 224rpx;
}
.nft-grid-item:active {
transform: scale(0.98);
}
/* 藏品信息 */
.nft-info {
padding: 10rpx 0;
text-align: center;
width: 192rpx;
}
.nft-name {
display: block;
font-size: 24rpx;
color: rgba(255, 255, 255, 0.9);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 加载更多 */
.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>