From 0359fd62cb6bd9561c30f46446a0de35c1b20d1b Mon Sep 17 00:00:00 2001
From: zhaoxing <2558691827@qq.com>
Date: Thu, 12 Nov 2026 18:28:37 +0800
Subject: [PATCH] =?UTF-8?q?feat(listings):=20=E7=BB=9F=E4=B8=80=E4=BA=BA?=
=?UTF-8?q?=E8=84=B8=E6=83=85=E5=86=B5=E6=96=87=E6=A1=88=E5=B9=B6=E4=BC=98?=
=?UTF-8?q?=E5=8C=96=E8=AF=A6=E6=83=85=E9=A1=B5=E5=B8=83=E5=B1=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../features/admin/AdminListingDetailPage.tsx | 2 +-
.../admin/AdminListingReviewDetailPage.tsx | 3 +-
.../features/admin/AdminOrderDetailPage.tsx | 16 +++----
.../src/features/admin/listingDetailModel.ts | 19 ++++-----
.../features/admin/orderDetailModel.test.ts | 37 ++++++++++++++++
.../src/features/admin/orderDetailModel.ts | 10 ++++-
frontend/src/features/listings/labels.test.ts | 19 +++++++++
frontend/src/features/listings/labels.ts | 6 ++-
.../features/seller/SellerListingFormPage.tsx | 6 ++-
frontend/src/styles/admin-listing-detail.css | 42 +++++++++++++++----
10 files changed, 126 insertions(+), 34 deletions(-)
create mode 100644 frontend/src/features/admin/orderDetailModel.test.ts
diff --git a/frontend/src/features/admin/AdminListingDetailPage.tsx b/frontend/src/features/admin/AdminListingDetailPage.tsx
index 8b28be5..bf409c4 100644
--- a/frontend/src/features/admin/AdminListingDetailPage.tsx
+++ b/frontend/src/features/admin/AdminListingDetailPage.tsx
@@ -407,7 +407,7 @@ export function AdminListingDetailPage() {
-
+
{assetRows.map(row => (
{row.value}
diff --git a/frontend/src/features/admin/AdminListingReviewDetailPage.tsx b/frontend/src/features/admin/AdminListingReviewDetailPage.tsx
index 27da716..74859ba 100644
--- a/frontend/src/features/admin/AdminListingReviewDetailPage.tsx
+++ b/frontend/src/features/admin/AdminListingReviewDetailPage.tsx
@@ -291,7 +291,6 @@ export function AdminListingReviewDetailPage() {
meta={
listing ? (
- {listing.review_status === 'pending' ? 待审核 : null}
@@ -389,7 +388,7 @@ export function AdminListingReviewDetailPage() {
size="small"
className="admin-detail-card admin-detail-card--wide"
>
-
+
{assetRows.map(row => (
{row.value}
diff --git a/frontend/src/features/admin/AdminOrderDetailPage.tsx b/frontend/src/features/admin/AdminOrderDetailPage.tsx
index c7e3ad2..de5ee46 100644
--- a/frontend/src/features/admin/AdminOrderDetailPage.tsx
+++ b/frontend/src/features/admin/AdminOrderDetailPage.tsx
@@ -712,7 +712,7 @@ export function AdminOrderDetailPage() {
-
+
{order.order_no}
@@ -734,7 +734,7 @@ export function AdminOrderDetailPage() {
-
+
{formatText(order.renter_phone)} · ID {order.renter_id}
@@ -759,7 +759,7 @@ export function AdminOrderDetailPage() {
-
+
{accountSourceLabel(order.account_source)}
@@ -809,7 +809,7 @@ export function AdminOrderDetailPage() {
/>
}
>
-
+
{moneyOrDash(refundStatus?.refund_amount_cent)}
@@ -869,7 +869,7 @@ export function AdminOrderDetailPage() {
/>
}
>
-
+
{formatMoney(order.offline_settlement_amount_cent)}
@@ -895,7 +895,7 @@ export function AdminOrderDetailPage() {
}
>
-
+
{formatMoney(order.checkout.display_amount_cent ?? 0)}
@@ -950,7 +950,7 @@ export function AdminOrderDetailPage() {
{order.active_dispute ? (
-
+
#{order.active_dispute.id}
{formatText(order.active_dispute.type)}
@@ -1024,7 +1024,7 @@ export function AdminOrderDetailPage() {
}
>
-
+
{snapshotText(snapshot.account_id)}
diff --git a/frontend/src/features/admin/listingDetailModel.ts b/frontend/src/features/admin/listingDetailModel.ts
index 1a86424..3030c46 100644
--- a/frontend/src/features/admin/listingDetailModel.ts
+++ b/frontend/src/features/admin/listingDetailModel.ts
@@ -1,5 +1,10 @@
import type { AdminListing } from '@/features/admin/types'
-import { listingResources, type ListingResourceRow } from '@/features/listings/labels'
+import {
+ faceOwnerText,
+ listingResources,
+ listingStatusMeta,
+ type ListingResourceRow,
+} from '@/features/listings/labels'
import { formatCoinM, formatMoney } from '@/shared/utils/format'
import {
@@ -67,7 +72,7 @@ export function adminListingAssetRows(listing: AdminListing): ListingRow[] {
{ label: '解锁德穆兰', value: listingAssetText(listing, 'unlock_demulan') },
{ label: '凌晨可响应', value: listingAssetText(listing, 'early_morning_response') },
{ label: '封禁记录', value: listingAssetText(listing, 'ban_record') },
- { label: '人脸情况', value: listingAssetText(listing, 'face_owner') },
+ { label: '人脸情况', value: faceOwnerText(listing.asset_summary) || '—' },
{ label: '预计可租', value: duration.days },
]
}
@@ -96,15 +101,7 @@ export function adminListingOwnerRows(listing: AdminListing): ListingRow[] {
{ label: '哈夫币', value: formatCoinM(listing.haf_coin_amount) },
{ label: '每日损耗', value: duration.dailyLoss || '—' },
{ label: '预计可租', value: duration.days },
- {
- label: '商品状态',
- value:
- listing.status === 'published'
- ? '已上架'
- : listing.status === 'rented'
- ? '租用中'
- : listing.status,
- },
+ { label: '商品状态', value: listingStatusMeta(listing.status).label },
]
}
diff --git a/frontend/src/features/admin/orderDetailModel.test.ts b/frontend/src/features/admin/orderDetailModel.test.ts
new file mode 100644
index 0000000..6acfeda
--- /dev/null
+++ b/frontend/src/features/admin/orderDetailModel.test.ts
@@ -0,0 +1,37 @@
+import { describe, expect, it } from 'vitest'
+
+import { orderFundRows } from '@/features/admin/orderDetailModel'
+import type { AdminOrderDetail } from '@/features/admin/types'
+
+function order(patch: Partial = {}): AdminOrderDetail {
+ return {
+ status: 'completed',
+ pure_coin_original_amount_cent: 0,
+ extra_item_original_amount_cent: 0,
+ rent_discount_amount_cent: 0,
+ actual_pure_coin_amount_cent: 0,
+ actual_pure_coin_discount_cent: 0,
+ growth_points_basis_cent: 0,
+ rent_amount_cent: 0,
+ owner_rent_amount_cent: 0,
+ platform_fee_cent: 0,
+ deposit_amount_cent: 0,
+ deposit_original_amount_cent: 0,
+ deposit_waived_amount_cent: 0,
+ ...patch,
+ } as AdminOrderDetail
+}
+
+describe('orderFundRows', () => {
+ it('优惠为 0 时不产生负零金额', () => {
+ const rows = orderFundRows(order())
+ const discount = rows.find(row => row.label === '最终实际纯币优惠')
+ expect(discount?.amountCent).toBe(0)
+ expect(Object.is(discount?.amountCent, -0)).toBe(false)
+ })
+
+ it('有优惠时展示为负数,便于区分扣减', () => {
+ const rows = orderFundRows(order({ actual_pure_coin_discount_cent: 940 }))
+ expect(rows.find(row => row.label === '最终实际纯币优惠')?.amountCent).toBe(-940)
+ })
+})
diff --git a/frontend/src/features/admin/orderDetailModel.ts b/frontend/src/features/admin/orderDetailModel.ts
index 15a0a5b..f7486bc 100644
--- a/frontend/src/features/admin/orderDetailModel.ts
+++ b/frontend/src/features/admin/orderDetailModel.ts
@@ -90,7 +90,10 @@ export function orderFundRows(order: AdminOrderDetail): OrderFundRow[] {
{ label: '原始租金', amountCent: numberOf(order.rent_original_amount_cent) },
{
label: `${order.renter_growth_level_name || '成长等级'}优惠`,
- amountCent: -numberOf(order.rent_discount_amount_cent),
+ amountCent:
+ numberOf(order.rent_discount_amount_cent) > 0
+ ? -numberOf(order.rent_discount_amount_cent)
+ : 0,
}
)
}
@@ -102,7 +105,10 @@ export function orderFundRows(order: AdminOrderDetail): OrderFundRow[] {
},
{
label: '最终实际纯币优惠',
- amountCent: -numberOf(order.actual_pure_coin_discount_cent),
+ amountCent:
+ numberOf(order.actual_pure_coin_discount_cent) > 0
+ ? -numberOf(order.actual_pure_coin_discount_cent)
+ : 0,
},
{
label: '积分计算纯币基数',
diff --git a/frontend/src/features/listings/labels.test.ts b/frontend/src/features/listings/labels.test.ts
index 90db8e2..4f199cd 100644
--- a/frontend/src/features/listings/labels.test.ts
+++ b/frontend/src/features/listings/labels.test.ts
@@ -1,6 +1,7 @@
import { describe, expect, it } from 'vitest'
import {
+ faceOwnerText,
listingPriceDetail,
listingRatioText,
listingResources,
@@ -149,3 +150,21 @@ describe('resourceBadgeText', () => {
)
})
})
+
+describe('faceOwnerText', () => {
+ it('把是/否映射为本人/非本人', () => {
+ expect(faceOwnerText({ face_owner: '是' })).toBe('本人')
+ expect(faceOwnerText({ face_owner: '否' })).toBe('非本人')
+ })
+
+ it('兼容已映射文案与空值', () => {
+ expect(faceOwnerText({ face_owner: '本人' })).toBe('本人')
+ expect(faceOwnerText({ face_owner: '非本人' })).toBe('非本人')
+ expect(faceOwnerText({ face_owner: ' ' })).toBe('')
+ expect(faceOwnerText(null)).toBe('')
+ })
+
+ it('未知文案原样保留', () => {
+ expect(faceOwnerText({ face_owner: '需配合人脸' })).toBe('需配合人脸')
+ })
+})
diff --git a/frontend/src/features/listings/labels.ts b/frontend/src/features/listings/labels.ts
index 9485d7c..3974a89 100644
--- a/frontend/src/features/listings/labels.ts
+++ b/frontend/src/features/listings/labels.ts
@@ -91,7 +91,11 @@ export function onlineTimeText(summary?: Record | null): string
export function faceOwnerText(summary?: Record | null): string {
const value = summary?.face_owner
if (typeof value !== 'string') return ''
- return value.trim()
+ const text = value.trim()
+ if (!text) return ''
+ if (text === '是' || text === '本人' || text === '有') return '本人'
+ if (text === '否' || text === '非本人' || text === '无') return '非本人'
+ return text
}
export function banRecordText(summary?: Record | null): string {
diff --git a/frontend/src/features/seller/SellerListingFormPage.tsx b/frontend/src/features/seller/SellerListingFormPage.tsx
index c0dd980..7412d0e 100644
--- a/frontend/src/features/seller/SellerListingFormPage.tsx
+++ b/frontend/src/features/seller/SellerListingFormPage.tsx
@@ -153,10 +153,11 @@ function ChoiceField(props: {
required?: boolean
value: string
options: string[]
+ optionLabels?: Record
placeholder?: string
onChange: (value: string) => void
}) {
- const { label, required, value, options, placeholder, onChange } = props
+ const { label, required, value, options, optionLabels, placeholder, onChange } = props
return (
@@ -182,7 +183,7 @@ function ChoiceField(props: {
onChange(option)
}}
>
- {option}
+ {optionLabels?.[option] ?? option}
)
})}
@@ -1183,6 +1184,7 @@ export function SellerListingFormPage({ mobile = false }: { mobile?: boolean } =
label="人脸情况"
value={form.face_owner}
options={options.face_options}
+ optionLabels={{ 是: '本人', 否: '非本人' }}
onChange={value => updateForm('face_owner', value)}
/>