From 23883d4be557871cc68a7570b0d1eb9f1e13bf16 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 6 Sep 2026 21:40:35 +0800 Subject: [PATCH] =?UTF-8?q?perf(listings):=20=E4=BC=98=E5=8C=96=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E9=A1=B5=E5=9B=BE=E7=89=87=E5=8A=A0=E8=BD=BD=E9=93=BE?= =?UTF-8?q?=E8=B7=AF=E6=94=AF=E6=8C=81=E5=85=AC=E5=BC=80=E5=8F=98=E4=BD=93?= =?UTF-8?q?=E4=B8=8E=E5=88=86=E7=BA=A7=E7=A7=92=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modules/listing/handler_public.go | 12 +++- backend/internal/modules/listing/presenter.go | 56 +++++++++++++++++++ .../internal/modules/listing/service_test.go | 27 +++++++++ .../listings/views/ListingDetailView.vue | 13 +++-- .../views/MobileListingDetailView.vue | 13 +++-- .../shared/components/business/AuthImage.vue | 22 +++++++- frontend/src/shared/utils/listingDisplay.ts | 36 ++++++++++++ 7 files changed, 168 insertions(+), 11 deletions(-) diff --git a/backend/internal/modules/listing/handler_public.go b/backend/internal/modules/listing/handler_public.go index b4955ff..d877ca5 100644 --- a/backend/internal/modules/listing/handler_public.go +++ b/backend/internal/modules/listing/handler_public.go @@ -60,7 +60,17 @@ func (h *Handler) Screenshot(c *gin.Context) { writeListingError(c, err) return } - h.writePublicObject(c, filemodule.ImageVariantFallbackKeys(key, filemodule.ImageVariantMedium)...) + variant := c.Query("variant") + var fallbackKeys []string + switch variant { + case "thumb": + fallbackKeys = filemodule.ImageVariantFallbackKeys(key, filemodule.ImageVariantThumb) + case "raw": + fallbackKeys = []string{key} + default: + fallbackKeys = filemodule.ImageVariantFallbackKeys(key, filemodule.ImageVariantMedium) + } + h.writePublicObject(c, fallbackKeys...) } func (h *Handler) writePublicObject(c *gin.Context, keys ...string) { diff --git a/backend/internal/modules/listing/presenter.go b/backend/internal/modules/listing/presenter.go index ba47c6e..f6bab7b 100644 --- a/backend/internal/modules/listing/presenter.go +++ b/backend/internal/modules/listing/presenter.go @@ -65,15 +65,71 @@ func sellerListings(items []ListingDTO) []ListingDTO { } func applyPublicListingURLs(item *ListingDTO) { + if item == nil { + return + } item.SourceChannel = "" item.IsExternalUpload = false + rawScreenshotURLs := item.ScreenshotURLS item.ScreenshotURLS = publicScreenshotURLs(item.ID, item.ScreenshotURLS, item.Status, item.ReviewStatus) if item.AssetSummary != nil { delete(item.AssetSummary, "import_meta") delete(item.AssetSummary, "price_breakdown") + applyPublicScreenshotGroups(item.ID, item.AssetSummary, rawScreenshotURLs, item.ScreenshotURLS) } } +func applyPublicScreenshotGroups(listingID uint64, assetSummary map[string]any, rawURLs []string, publicURLs []string) { + rawGroups, ok := assetSummary["screenshot_groups"].(map[string]any) + if !ok { + return + } + urlMap := make(map[string]string, len(rawURLs)) + keyMap := make(map[string]string, len(rawURLs)) + for i, rawURL := range rawURLs { + if i < len(publicURLs) { + urlMap[rawURL] = publicURLs[i] + if key := extractListingObjectKey(rawURL); key != "" { + keyMap[key] = publicURLs[i] + } + } + } + newGroups := make(map[string]any, len(rawGroups)) + for groupKey, groupVal := range rawGroups { + switch list := groupVal.(type) { + case []string: + converted := make([]string, len(list)) + for i, u := range list { + if pub, found := urlMap[u]; found { + converted[i] = pub + } else if key := extractListingObjectKey(u); key != "" && keyMap[key] != "" { + converted[i] = keyMap[key] + } else { + converted[i] = u + } + } + newGroups[groupKey] = converted + case []any: + converted := make([]string, len(list)) + for i, v := range list { + if s, ok := v.(string); ok { + if pub, found := urlMap[s]; found { + converted[i] = pub + } else if key := extractListingObjectKey(s); key != "" && keyMap[key] != "" { + converted[i] = keyMap[key] + } else { + converted[i] = s + } + } + } + newGroups[groupKey] = converted + default: + newGroups[groupKey] = groupVal + } + } + assetSummary["screenshot_groups"] = newGroups +} + func applySellerListingPrice(item *ListingDTO) { if item == nil { return diff --git a/backend/internal/modules/listing/service_test.go b/backend/internal/modules/listing/service_test.go index 21a014a..2ccb380 100644 --- a/backend/internal/modules/listing/service_test.go +++ b/backend/internal/modules/listing/service_test.go @@ -672,3 +672,30 @@ func containsString(values []string, target string) bool { } return false } + +func TestApplyPublicScreenshotGroups(t *testing.T) { + rawURLs := []string{ + "/api/files/object?key=listing/coin.png", + "/api/files/object?key=listing/skin1.png", + } + publicURLs := []string{ + "/api/listings/88/screenshots/0", + "/api/listings/88/screenshots/1", + } + summary := map[string]any{ + "screenshot_groups": map[string]any{ + "coin": []any{"/api/files/object?key=listing/coin.png"}, + "skin": []string{"/api/files/object?key=listing/skin1.png"}, + }, + } + applyPublicScreenshotGroups(88, summary, rawURLs, publicURLs) + groups := summary["screenshot_groups"].(map[string]any) + coinList := groups["coin"].([]string) + if len(coinList) != 1 || coinList[0] != "/api/listings/88/screenshots/0" { + t.Fatalf("expected /api/listings/88/screenshots/0, got %#v", coinList) + } + skinList := groups["skin"].([]string) + if len(skinList) != 1 || skinList[0] != "/api/listings/88/screenshots/1" { + t.Fatalf("expected /api/listings/88/screenshots/1, got %#v", skinList) + } +} diff --git a/frontend/src/features/listings/views/ListingDetailView.vue b/frontend/src/features/listings/views/ListingDetailView.vue index 2845a24..e824de5 100644 --- a/frontend/src/features/listings/views/ListingDetailView.vue +++ b/frontend/src/features/listings/views/ListingDetailView.vue @@ -40,6 +40,9 @@ import { readAssetString, getRatioValue, isTopTierInsurance, + getScreenshotThumbURL, + getScreenshotMediumURL, + getScreenshotRawURL, type ListingDisplayResource, } from '@/shared/utils/listingDisplay' @@ -165,7 +168,9 @@ const detailScreenshots = computed(() => { url, })) }) -const detailScreenshotUrls = computed(() => detailScreenshots.value.map(shot => shot.url)) +const detailScreenshotRawUrls = computed(() => + detailScreenshots.value.map(shot => getScreenshotRawURL(shot.url)) +) const activeScreenshot = computed(() => { if (detailScreenshots.value.length === 0) return null @@ -533,12 +538,12 @@ function goBack() {