diff --git a/backend/internal/modules/listing/repository.go b/backend/internal/modules/listing/repository.go index 5d8c02f..d85126f 100644 --- a/backend/internal/modules/listing/repository.go +++ b/backend/internal/modules/listing/repository.go @@ -378,7 +378,7 @@ func (r *Repository) ListMine(ownerID uint64) ([]ListingDTO, error) { if err != nil { return nil, err } - return rowsToDTO(rows), nil + return sellerListings(rowsToDTO(rows)), nil } func (r *Repository) FindPublic(id uint64) (*ListingDTO, error) { @@ -412,7 +412,12 @@ func (r *Repository) FindPublicScreenshotKey(id uint64, index int) (string, erro } func (r *Repository) FindMine(ownerID uint64, id uint64) (*ListingDTO, error) { - return r.findDTO("l.id = ? AND l.owner_id = ?", id, ownerID) + dto, err := r.findDTO("l.id = ? AND l.owner_id = ?", id, ownerID) + if err != nil { + return nil, err + } + applySellerListingPrice(dto) + return dto, nil } func (r *Repository) findOwnedForUpdate(tx *gorm.DB, ownerID uint64, listingID uint64) (*model.RentalListing, *model.GameAccount, error) { @@ -493,6 +498,13 @@ func publicListings(items []ListingDTO) []ListingDTO { return items } +func sellerListings(items []ListingDTO) []ListingDTO { + for index := range items { + applySellerListingPrice(&items[index]) + } + return items +} + func applyPublicListingURLs(item *ListingDTO) { item.ScreenshotURLS = publicScreenshotURLs(item.ID, item.ScreenshotURLS, item.Status, item.ReviewStatus) if item.AssetSummary != nil { @@ -500,6 +512,20 @@ func applyPublicListingURLs(item *ListingDTO) { } } +func applySellerListingPrice(item *ListingDTO) { + if item == nil || item.AssetSummary == nil { + return + } + breakdown, ok := item.AssetSummary["price_breakdown"].(map[string]any) + if !ok { + return + } + sellerPrice := readSummaryNumber(breakdown["seller_total_price"]) + if sellerPrice > 0 { + item.Price = sellerPrice + } +} + func (row listingRow) toDTO() ListingDTO { assetSummary := decodeAssetSummary(row.AssetSummary) screenshotURLS := cleanScreenshotURLs(decodeScreenshots(row.ScreenshotURLS)) diff --git a/backend/internal/modules/listing/service_test.go b/backend/internal/modules/listing/service_test.go index 74543e2..392fee9 100644 --- a/backend/internal/modules/listing/service_test.go +++ b/backend/internal/modules/listing/service_test.go @@ -40,3 +40,37 @@ func TestValidateRequestRequiresDepositAboveConsumables(t *testing.T) { t.Fatalf("expected valid request, got %v", err) } } + +func TestApplySellerListingPriceUsesSellerTotalPrice(t *testing.T) { + item := &ListingDTO{ + Price: 238, + AssetSummary: map[string]any{ + "price_breakdown": map[string]any{ + "seller_total_price": 200, + }, + }, + } + + applySellerListingPrice(item) + + if item.Price != 200 { + t.Fatalf("expected seller price 200, got %.2f", item.Price) + } +} + +func TestApplySellerListingPriceKeepsFallbackPrice(t *testing.T) { + item := &ListingDTO{ + Price: 238, + AssetSummary: map[string]any{ + "price_breakdown": map[string]any{ + "seller_total_price": 0, + }, + }, + } + + applySellerListingPrice(item) + + if item.Price != 238 { + t.Fatalf("expected fallback price 238, got %.2f", item.Price) + } +} diff --git a/frontend/src/utils/listingDisplay.ts b/frontend/src/utils/listingDisplay.ts index 4de9708..3fba7a8 100644 --- a/frontend/src/utils/listingDisplay.ts +++ b/frontend/src/utils/listingDisplay.ts @@ -30,6 +30,15 @@ export function getListingDisplayPrice(item: Listing) { return Number(item.price || 0); } +export function getListingSellerPrice(item: Listing) { + const priceBreakdown = item.asset_summary?.price_breakdown; + if (typeof priceBreakdown === "object" && priceBreakdown !== null) { + const price = readUnknownNumber((priceBreakdown as Record).seller_total_price); + if (price > 0) return price; + } + return getListingDisplayPrice(item); +} + export function getRatioValue(item: Listing) { const ratio = readAssetNumber(item, "publish_ratio"); if (ratio > 0) return ratio; diff --git a/frontend/src/views/mobile/MobileSellerListingsView.vue b/frontend/src/views/mobile/MobileSellerListingsView.vue index 4847bb3..fb1e08c 100644 --- a/frontend/src/views/mobile/MobileSellerListingsView.vue +++ b/frontend/src/views/mobile/MobileSellerListingsView.vue @@ -4,11 +4,11 @@ import { useRouter } from 'vue-router' import { showToast, showDialog } from 'vant' import { fetchSellerListings, offlineListing, submitListingReview, type Listing } from '@/api/listings' import { fetchFileBlobByURL } from '@/api/files' -import { listingReviewStatusLabel, listingStatusLabel } from '@/utils/statusLabels' +import { listingStatusLabel } from '@/utils/statusLabels' +import { getListingSellerPrice } from '@/utils/listingDisplay' const router = useRouter() const loading = ref(false) -const rawListings = ref([]) const activeTab = ref('all') interface DisplayListing extends Listing { @@ -128,12 +128,8 @@ function getStatusText(item: Listing) { return listingStatusLabel(item.status) } -function goDetail(item: Listing) { - if (item.status === 'published' && item.review_status === 'approved') { - router.push(`/m/listings/${item.id}`) - } else { - showToast('该商品当前状态不支持预览') - } +function listingPrice(item: Listing) { + return getListingSellerPrice(item).toFixed(2) } function goBack() { @@ -178,7 +174,6 @@ function goBack() { v-for="item in filteredListings" :key="item.id" class="listing-card" - @click="goDetail(item)" >
@@ -201,7 +196,7 @@ function goBack() {

{{ item.server_region }} · {{ item.login_platform }}

- ¥{{ item.price.toFixed(2) }}/小时 + ¥{{ listingPrice(item) }} 押金: ¥{{ item.deposit_amount.toFixed(2) }}
@@ -352,7 +347,6 @@ function goBack() { padding: 14px; box-shadow: 0 4px 18px rgba(0, 0, 0, 0.02), 0 1px 4px rgba(0, 0, 0, 0.02); border: 1px solid rgba(243, 244, 246, 0.9); - cursor: pointer; display: flex; flex-direction: column; } diff --git a/frontend/src/views/seller/SellerListingsView.vue b/frontend/src/views/seller/SellerListingsView.vue index aa319df..9c3995d 100644 --- a/frontend/src/views/seller/SellerListingsView.vue +++ b/frontend/src/views/seller/SellerListingsView.vue @@ -4,6 +4,7 @@ import { onMounted, ref } from 'vue' import { fetchSellerListings, offlineListing, submitListingReview, type Listing } from '@/api/listings' import { listingReviewStatusLabel, listingStatusLabel } from '@/utils/statusLabels' +import { getListingSellerPrice } from '@/utils/listingDisplay' const loading = ref(false) const listings = ref([]) @@ -36,16 +37,7 @@ async function offline(id: number) { } function listingPrice(row: Listing) { - return `¥${readSellerPrice(row).toFixed(2)}` -} - -function readSellerPrice(row: Listing) { - const breakdown = row.asset_summary?.price_breakdown - if (typeof breakdown === 'object' && breakdown !== null) { - const price = Number((breakdown as Record).seller_total_price) - if (Number.isFinite(price) && price > 0) return price - } - return Number(row.price || 0) + return `¥${getListingSellerPrice(row).toFixed(2)}` }