68 lines
1.7 KiB
Vue
68 lines
1.7 KiB
Vue
<template>
|
||
<!-- 只渲染背景图,卡片由父组件 BannerCarousel 渲染在 swiper 外层 -->
|
||
<view class="banner-top3-bg" @tap="onBannerTap">
|
||
<image class="banner-bg" src="/static/square/paihangbang.png" mode="aspectFill" />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted } from 'vue';
|
||
import { getHotRankingApi, getOssPresignedUrlApi } from '@/utils/api.js';
|
||
|
||
const emit = defineEmits(['dataLoaded']);
|
||
|
||
const resolveOssUrl = async (fileName, type) => {
|
||
if (!fileName) return '';
|
||
try {
|
||
const res = await getOssPresignedUrlApi(fileName, 3600, type);
|
||
if (res?.code === 200 && res.data?.url) return res.data.url;
|
||
} catch (e) {
|
||
console.warn('[BannerTop3] OSS URL 获取失败', fileName, e?.message);
|
||
}
|
||
return fileName;
|
||
};
|
||
|
||
const loadTop3 = async () => {
|
||
try {
|
||
const res = await getHotRankingApi('total', null, 1, 3);
|
||
if (res.code === 200 && res.data?.items) {
|
||
const items = res.data.items.slice(0, 3);
|
||
const resolved = await Promise.all(items.map(async (item) => {
|
||
const [coverUrl, avatarUrl] = await Promise.all([
|
||
resolveOssUrl(item.cover_url || '', 'asset'),
|
||
resolveOssUrl(item.avatar_url || '', 'avatar'),
|
||
]);
|
||
return { ...item, cover_url: coverUrl, avatar_url: avatarUrl };
|
||
}));
|
||
emit('dataLoaded', resolved);
|
||
}
|
||
} catch (e) {
|
||
console.error('[BannerTop3] 加载失败', e?.message ?? e);
|
||
}
|
||
};
|
||
|
||
const onBannerTap = () => {
|
||
uni.navigateTo({ url: '/pages/rank/rank' });
|
||
};
|
||
|
||
onMounted(loadTop3);
|
||
defineExpose({ reload: loadTop3 });
|
||
</script>
|
||
|
||
<style scoped>
|
||
.banner-top3-bg {
|
||
width: 100%;
|
||
height: 360rpx;
|
||
position: relative;
|
||
overflow: hidden;
|
||
border-radius: 24rpx;
|
||
}
|
||
|
||
.banner-bg {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
</style>
|