topfans/frontend/pages/components/StarbookContent.vue
2026-04-12 16:05:13 +08:00

257 lines
5.8 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="starbook-content">
<!-- 背景图片 -->
<image class="background-image" src="/static/background/starbook.jpg" mode="aspectFill"></image>
<!-- 内容区域 -->
<view class="content-wrapper">
<!-- NFT卡片网格容器 -->
<view class="nft-grid-container">
<view
v-for="(item, index) in nftList"
:key="index"
class="nft-grid-item"
>
<NftCard
:cover-image="item.image"
:width="cardSize"
:height="cardSize"
:locked="item.locked"
:show-add-button="!item.locked && !item.image"
operation="place"
:custom-style="cardCustomStyle"
@add="handleAddNft"
@click="handleCardClick(item, index)"
/>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted, onActivated, watch } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import NftCard from './NftCard.vue';
import { getMyAssetsApi } from '@/utils/api.js';
import { getAssetCoverRealUrl } from '@/utils/assetImageHelper.js';
// 屏幕宽度
const screenWidth = ref(0);
// 加载状态
const loading = ref(false);
// NFT列表初始为15个卡片将通过API填充
const nftList = ref([]);
// 计算卡片尺寸
const cardSize = computed(() => {
if (screenWidth.value === 0) return 200;
// 每行3个卡片留出padding和间距
// rpx转px1rpx = screenWidth / 750
const rpxToPx = screenWidth.value / 750;
const padding = 40 * rpxToPx; // 左右各40rpx
const gap = 15 * rpxToPx; // 卡片间距15rpx3列有2个间距
// 可用宽度 = 屏幕宽度 - 左右padding - 2个间距
const availableWidth = screenWidth.value - (padding * 2) - (gap * 2);
return Math.floor(availableWidth / 3);
});
// 卡片自定义样式
const cardCustomStyle = {
position: 'absolute',
top: '0',
left: '0'
};
// 添加NFT处理 - 跳转到铸爱页面
const handleAddNft = () => {
// 跳转到铸爱商城页面
uni.navigateTo({
url: '/pages/castlove/mall'
});
};
// 加载藏品列表
const loadAssetsList = async () => {
loading.value = true;
try {
const response = await getMyAssetsApi(1, 20);
if (response.code === 200 && response.data && response.data.items) {
// 映射后端数据并解析封面URL
const assetsPromises = response.data.items.map(async item => {
const realCoverUrl = await getAssetCoverRealUrl(item.cover_url);
return {
asset_id: item.asset_id,
name: item.name,
image: realCoverUrl,
cover_url: item.cover_url || '/static/nft/collection.png',
tx_hash: item.tx_hash,
like_count: item.like_count,
status: item.status,
locked: false
};
});
const assets = await Promise.all(assetsPromises);
// 添加一个空白卡片用于添加新藏品
assets.push({ image: '', locked: false });
// 填充剩余位置为锁定卡片总共15个卡片
const totalCards = 15;
const remainingCards = totalCards - assets.length;
for (let i = 0; i < remainingCards; i++) {
assets.push({ image: '', locked: true });
}
nftList.value = assets;
}
} catch (error) {
console.error('获取藏品列表失败:', error);
uni.showToast({
title: error.message || '获取藏品列表失败',
icon: 'none',
duration: 2000
});
// 失败时使用默认布局1个空白卡片 + 14个锁定卡片
const defaultList = [{ image: '', locked: false }];
for (let i = 0; i < 14; i++) {
defaultList.push({ image: '', locked: true });
}
nftList.value = defaultList;
} finally {
loading.value = false;
}
};
// 点击卡片跳转到详情页
const handleCardClick = (item) => {
if (item.image && !item.locked && item.asset_id) {
uni.navigateTo({
url: `/pages/asset-detail/asset-detail?asset_id=${item.asset_id}`
});
}
};
// 定义 props 用于接收父组件的显示状态
const props = defineProps({
isActive: {
type: Boolean,
default: false
}
});
onMounted(() => {
const systemInfo = uni.getSystemInfoSync();
screenWidth.value = systemInfo.windowWidth;
// 加载藏品列表
loadAssetsList();
});
// 每次组件激活时重新加载数据keep-alive场景
onActivated(() => {
loadAssetsList();
});
// 监听页面显示事件(页面级切换场景)
onShow(() => {
loadAssetsList();
});
// 监听 isActive prop 变化tab切换场景
watch(() => props.isActive, (newValue, oldValue) => {
if (newValue && !oldValue) {
loadAssetsList();
}
});
</script>
<style scoped>
.starbook-content {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 1;
overflow-y: auto;
overflow-x: hidden;
background: #0d0820;
}
/* 滚动条样式 - 自动隐藏 */
.starbook-content::-webkit-scrollbar {
width: 6rpx;
}
.starbook-content::-webkit-scrollbar-track {
background: transparent;
}
.starbook-content::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.3);
border-radius: 10rpx;
transition: background 0.3s ease;
}
.starbook-content::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.5);
}
.background-image {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 0;
object-fit: cover;
min-width: 100%;
min-height: 100%;
}
.content-wrapper {
position: relative;
z-index: 1;
width: 100%;
min-height: 100%;
padding: 250rpx 30rpx;
box-sizing: border-box;
}
/* NFT网格容器 */
.nft-grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* 列间距(与计算逻辑保持一致) */
column-gap: 15rpx;
/* 行间距 */
row-gap: 10rpx;
width: 100%;
max-width: 100%;
/* 确保网格项靠上对齐 */
align-items: start;
justify-items: center;
}
.nft-grid-item {
position: relative;
width: 100%;
/* 保持3:4比例 */
padding-top: 133.33%;
/* 确保内容靠上对齐 */
display: block;
}
</style>