revert(listings): 首页卡片恢复使用原生 img 与公开缩略图链路 (16KB秒开)

This commit is contained in:
yml2213
2026-09-06 20:36:25 +08:00
parent ac909d6757
commit 823632b608
5 changed files with 19 additions and 74 deletions
@@ -2,7 +2,6 @@
import { computed } from 'vue' import { computed } from 'vue'
import { RouterLink } from 'vue-router' import { RouterLink } from 'vue-router'
import type { Listing } from '@/features/listings' import type { Listing } from '@/features/listings'
import AuthImage from '@/shared/components/business/AuthImage.vue'
import { formatCent, formatMoney } from '@/shared/utils/money' import { formatCent, formatMoney } from '@/shared/utils/money'
import { import {
formatEstimatedRentalDuration, formatEstimatedRentalDuration,
@@ -23,7 +22,6 @@ import {
formatHafCoinM, formatHafCoinM,
readAssetString, readAssetString,
isTopTierInsurance, isTopTierInsurance,
getCoinScreenshotURL,
type ListingDisplayResource, type ListingDisplayResource,
} from '@/shared/utils/listingDisplay' } from '@/shared/utils/listingDisplay'
@@ -33,8 +31,8 @@ interface Props {
const props = defineProps<Props>() const props = defineProps<Props>()
// 封面图片:仅展示纯币截图单张,避免 OSS 爆发高频请求错误 // 封面图片:优先使用后端生成的公开缩略图(16KB秒开,免鉴权)
const coverURL = computed(() => getCoinScreenshotURL(props.listing)) const coverURL = computed(() => props.listing.cover_url || props.listing.screenshot_urls?.[0] || '')
// 基础元信息 // 基础元信息
const listingCode = computed(() => formatListingCode(props.listing)) const listingCode = computed(() => formatListingCode(props.listing))
@@ -102,15 +100,15 @@ function formatStatNumber(value: number) {
<template> <template>
<RouterLink class="hfb-listing-card" :to="`/listings/${listing.id}`"> <RouterLink class="hfb-listing-card" :to="`/listings/${listing.id}`">
<!-- 左侧:4:3 黄金比例单张封面(展示纯币截图) --> <!-- 左侧:4:3 黄金比例单张封面(后端公开缩略图,秒级加载) -->
<div class="card-media"> <div class="card-media">
<AuthImage <img
v-if="coverURL" v-if="coverURL"
:source="coverURL" :src="coverURL"
:alt="getListingTitle(listing)" :alt="getListingTitle(listing)"
image-class="media-img" loading="lazy"
fallback-class="media-fallback" decoding="async"
fit="cover" class="media-img"
/> />
<div v-else class="media-empty">HFB</div> <div v-else class="media-empty">HFB</div>
@@ -299,7 +297,6 @@ function formatStatNumber(value: number) {
cursor: pointer; cursor: pointer;
} }
.card-media :deep(img),
.card-media img { .card-media img {
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -308,25 +305,10 @@ function formatStatNumber(value: number) {
transition: transform 0.25s ease; transition: transform 0.25s ease;
} }
.hfb-listing-card:hover .card-media :deep(img),
.hfb-listing-card:hover .card-media img { .hfb-listing-card:hover .card-media img {
transform: scale(1.03); transform: scale(1.03);
} }
.card-media :deep(.auth-image-fallback) {
width: 100%;
height: 100%;
min-height: 100%;
border: none;
border-radius: 0;
background: #f1f5f9;
color: #94a3b8;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.media-empty { .media-empty {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -9,7 +9,6 @@ import {
useListingCollections, useListingCollections,
type ListingCollectionItem, type ListingCollectionItem,
} from '@/features/listings/composables/useListingCollections' } from '@/features/listings/composables/useListingCollections'
import AuthImage from '@/shared/components/business/AuthImage.vue'
import { formatCent, formatMoney } from '@/shared/utils/money' import { formatCent, formatMoney } from '@/shared/utils/money'
import { import {
formatHafCoinM, formatHafCoinM,
@@ -17,7 +16,6 @@ import {
getCoinWan, getCoinWan,
getListingDisplayPrice, getListingDisplayPrice,
getListingTitle, getListingTitle,
getCoinScreenshotURL,
} from '@/shared/utils/listingDisplay' } from '@/shared/utils/listingDisplay'
const route = useRoute() const route = useRoute()
@@ -138,11 +136,12 @@ function timeText(item: ListingCollectionItem) {
<section v-else class="mobile-list"> <section v-else class="mobile-list">
<article v-for="item in activeItems" :key="item.listing.id" class="mobile-card"> <article v-for="item in activeItems" :key="item.listing.id" class="mobile-card">
<RouterLink :to="detailPath(item)" class="mobile-card-main"> <RouterLink :to="detailPath(item)" class="mobile-card-main">
<AuthImage <img
v-if="getCoinScreenshotURL(item.listing)" v-if="item.listing.cover_url || item.listing.screenshot_urls?.[0]"
:source="getCoinScreenshotURL(item.listing)" :src="item.listing.cover_url || item.listing.screenshot_urls?.[0]"
:alt="getListingTitle(item.listing)" :alt="getListingTitle(item.listing)"
fit="cover" loading="lazy"
decoding="async"
/> />
<div v-else class="mobile-cover-empty">HFB</div> <div v-else class="mobile-cover-empty">HFB</div>
<div class="mobile-info"> <div class="mobile-info">
@@ -728,20 +728,6 @@
display: block; display: block;
} }
.mobile-card-media .auth-image-fallback {
width: 100%;
height: 100%;
min-height: 100%;
border: none;
border-radius: 0;
background: #f1f5f9;
color: #94a3b8;
font-size: 11px;
display: flex;
align-items: center;
justify-content: center;
}
.media-empty { .media-empty {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -53,7 +53,6 @@ import {
hasAcceleratedSaleRatio, hasAcceleratedSaleRatio,
hasGiftResources, hasGiftResources,
isTopTierInsurance, isTopTierInsurance,
getCoinScreenshotURL,
getCoinWan, getCoinWan,
formatHafCoinM, formatHafCoinM,
readAssetString, readAssetString,
@@ -1046,13 +1045,12 @@ syncMobileHomeQuery()
<div class="mobile-card-body"> <div class="mobile-card-body">
<!-- 左侧封面 --> <!-- 左侧封面 -->
<div class="mobile-card-media"> <div class="mobile-card-media">
<AuthImage <img
v-if="getCoinScreenshotURL(item)" v-if="item.cover_url || item.screenshot_urls?.[0]"
:source="getCoinScreenshotURL(item)" :src="item.cover_url || item.screenshot_urls?.[0]"
:alt="formatListingCode(item)" :alt="formatListingCode(item)"
image-class="mobile-media-img" loading="lazy"
fallback-class="mobile-media-fallback" decoding="async"
fit="cover"
/> />
<div v-else class="media-empty">HFB</div> <div v-else class="media-empty">HFB</div>
+1 -21
View File
@@ -411,28 +411,8 @@ export function isTopTierInsurance(value: string | undefined | null): boolean {
} }
/** /**
* 获取账号封面/纯币截图(仅展示一张,优先纯币截图,其次封面图,其次首张截图) * 获取账号封面图(优先公开缩略图接口,其次首张截图)
*/ */
export function getCoinScreenshotURL(item: Listing): string { export function getCoinScreenshotURL(item: Listing): string {
const groups = item.asset_summary?.screenshot_groups
if (typeof groups === 'object' && groups !== null) {
const groupRecord = groups as Record<string, unknown>
const orderedKeys = ['coin', 'tencentSecurity', 'skin', 'gameId', 'totalAsset']
for (const key of orderedKeys) {
const urls = groupRecord[key]
if (Array.isArray(urls)) {
const found = urls.find(url => typeof url === 'string' && Boolean(url))
if (found) return found
}
}
for (const key of Object.keys(groupRecord)) {
if (orderedKeys.includes(key)) continue
const urls = groupRecord[key]
if (Array.isArray(urls)) {
const found = urls.find(url => typeof url === 'string' && Boolean(url))
if (found) return found
}
}
}
return item.cover_url || item.screenshot_urls?.[0] || '' return item.cover_url || item.screenshot_urls?.[0] || ''
} }