From a2a9ade68e4e1c6d93b17e3ef7fd707764503758 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Mon, 13 Jul 2026 21:14:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A7=BB=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E8=81=9A=E7=84=A6=E6=94=BE=E5=A4=A7=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E8=A1=A5=E5=85=A8=E5=95=86=E5=93=81=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E4=BB=B7=E6=A0=BC=E6=8B=86=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 触控设备输入框字号至少 16px,避免 iOS Safari 聚焦自动放大 - 商品管理详情「号主与价格」对齐订单资金拆分字段展示 --- .../admin/views/AdminListingDetailView.vue | 87 ++++++++++++++++--- .../listings/views/MobileHomeFilterSheet.vue | 3 +- .../listings/views/MobileHomeView.css | 3 +- .../components/OrderResourceUsageEditor.vue | 3 +- .../orders/views/MobileOrderDetailView.vue | 3 +- .../views/MobileSellerListingCreateView.css | 3 +- frontend/src/styles/base.css | 15 ++++ 7 files changed, 99 insertions(+), 18 deletions(-) diff --git a/frontend/src/features/admin/views/AdminListingDetailView.vue b/frontend/src/features/admin/views/AdminListingDetailView.vue index 236e0ad..f5fc860 100644 --- a/frontend/src/features/admin/views/AdminListingDetailView.vue +++ b/frontend/src/features/admin/views/AdminListingDetailView.vue @@ -9,7 +9,11 @@ import { fetchAdminUsers, type AdminUserItem } from '@/features/admin/api/adminU import { fetchAdminFileBlob } from '@/shared/api/files' import AuthImage from '@/shared/components/business/AuthImage.vue' import { adminPath } from '@/shared/utils/adminPath' -import { formatCentWithSymbol } from '@/shared/utils/money' +import { + formatCentWithSymbol, + formatMoneyWithSymbol, + roundMoney, +} from '@/shared/utils/money' import { adminMarkListingAbnormal, adminOfflineListing, @@ -31,7 +35,9 @@ import { getCoinWan, getDailyLoss, getListingConsumablePrice, + getListingDisplayPrice, getListingResources, + getListingSellerPrice, getOnlineTimeText, getResourceQuantity, getSkinNames, @@ -88,21 +94,28 @@ const assetRows = computed(() => { }) const ownerRows = computed(() => { if (!listing.value) return [] + const row = listing.value + const renterPrice = buyerTotalPrice(row) + const ownerCoinBase = sellerCoinBasePrice(row) + const ownerLoss = getListingConsumablePrice(row) + const ownerTotal = sellerTotalPrice(row) + const platformFee = platformMarkupAmount(row) return [ { label: '号主', - value: listing.value.owner_phone || listing.value.owner_nickname || listing.value.owner_id, - }, - { label: '号主 ID', value: listing.value.owner_id }, - { label: '价格', value: listingPrice(listing.value) }, - { label: '押金', value: moneyCent(listing.value.deposit_amount_cent) }, - { label: '哈夫币', value: formatHafCoinM(getCoinWan(listing.value)) }, - { label: '每日损耗', value: getDailyLoss(listing.value) || '-' }, - { label: '预计可租', value: formatEstimatedRentalDuration(listing.value) }, - { - label: '额外消耗', - value: moneyCent(Math.round(getListingConsumablePrice(listing.value) * 100)), + value: row.owner_phone || row.owner_nickname || row.owner_id, }, + { label: '号主 ID', value: row.owner_id }, + // 价格字段与订单详情「资金拆分」对齐,便于客服核对 + { label: '租客租金', value: moneyYuan(renterPrice) }, + { label: '号主纯币价格', value: moneyYuan(ownerCoinBase) }, + { label: '号主损耗', value: moneyYuan(ownerLoss) }, + { label: '号主租金合计', value: moneyYuan(ownerTotal) }, + { label: '平台费用', value: moneyYuan(platformFee) }, + { label: '押金', value: moneyCent(row.deposit_amount_cent) }, + { label: '哈夫币', value: formatHafCoinM(getCoinWan(row)) }, + { label: '每日损耗', value: getDailyLoss(row) || '-' }, + { label: '预计可租', value: formatEstimatedRentalDuration(row) }, ] }) const resourceCards = computed(() => { @@ -240,8 +253,56 @@ function moneyCent(value: number) { return formatCentWithSymbol(value) } +function moneyYuan(value: number) { + return formatMoneyWithSymbol(value) +} + function listingPrice(row: Listing) { - return moneyCent(row.price_cent) + return moneyYuan(buyerTotalPrice(row)) +} + +function priceBreakdown(row: Listing) { + const breakdown = row.asset_summary?.price_breakdown + return typeof breakdown === 'object' && breakdown !== null + ? (breakdown as Record) + : {} +} + +function breakdownNumber(row: Listing, key: string) { + const value = priceBreakdown(row)[key] + if (typeof value === 'number') return value + if (typeof value === 'string' && value.trim()) { + const parsed = Number(value) + return Number.isFinite(parsed) ? parsed : 0 + } + return 0 +} + +/** 租客侧展示总价(含平台加价与额外消耗) */ +function buyerTotalPrice(row: Listing) { + const value = breakdownNumber(row, 'buyer_total_price') + return value > 0 ? roundMoney(value) : roundMoney(getListingDisplayPrice(row)) +} + +/** 号主纯币基础价 */ +function sellerCoinBasePrice(row: Listing) { + const value = breakdownNumber(row, 'seller_coin_base_price') + if (value > 0) return roundMoney(value) + return Math.max(0, roundMoney(sellerTotalPrice(row) - getListingConsumablePrice(row))) +} + +/** 号主租金合计 = 纯币基础价 + 额外消耗 */ +function sellerTotalPrice(row: Listing) { + const value = breakdownNumber(row, 'seller_total_price') + if (value > 0) return roundMoney(value) + return roundMoney(getListingSellerPrice(row)) +} + +/** 平台费用 = 租客价 - 号主价 */ +function platformMarkupAmount(row: Listing) { + const value = breakdownNumber(row, 'platform_markup_amount') + if (value > 0) return roundMoney(value) + return Math.max(0, roundMoney(buyerTotalPrice(row) - sellerTotalPrice(row))) } function assetText(row: Listing, key: string) { diff --git a/frontend/src/features/listings/views/MobileHomeFilterSheet.vue b/frontend/src/features/listings/views/MobileHomeFilterSheet.vue index aacb4c0..b79bafd 100644 --- a/frontend/src/features/listings/views/MobileHomeFilterSheet.vue +++ b/frontend/src/features/listings/views/MobileHomeFilterSheet.vue @@ -464,7 +464,8 @@ function sectionTopInBody(section: HTMLElement, body: HTMLElement) { border-radius: 8px; background: #fff; color: #333; - font-size: 13px; + /* iOS Safari:font-size < 16px 时聚焦会自动放大页面,需手动缩小才能恢复 */ + font-size: 16px; text-align: center; } diff --git a/frontend/src/features/listings/views/MobileHomeView.css b/frontend/src/features/listings/views/MobileHomeView.css index e96878f..8f9d8d7 100644 --- a/frontend/src/features/listings/views/MobileHomeView.css +++ b/frontend/src/features/listings/views/MobileHomeView.css @@ -81,7 +81,8 @@ } .home-search :deep(.van-field__control) { - font-size: 14px; + /* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */ + font-size: 16px; } .mobile-service { diff --git a/frontend/src/features/orders/components/OrderResourceUsageEditor.vue b/frontend/src/features/orders/components/OrderResourceUsageEditor.vue index 607f6dd..20edf46 100644 --- a/frontend/src/features/orders/components/OrderResourceUsageEditor.vue +++ b/frontend/src/features/orders/components/OrderResourceUsageEditor.vue @@ -634,7 +634,8 @@ function updateNumberField(field: 'coin_consumed_m' | 'otherAmountYuan', event: border: none; outline: none; background: transparent; - font-size: 14px; + /* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */ + font-size: 16px; color: #182232; } diff --git a/frontend/src/features/orders/views/MobileOrderDetailView.vue b/frontend/src/features/orders/views/MobileOrderDetailView.vue index 7514f16..9a8cfc7 100644 --- a/frontend/src/features/orders/views/MobileOrderDetailView.vue +++ b/frontend/src/features/orders/views/MobileOrderDetailView.vue @@ -821,7 +821,8 @@ async function copyListingCode() { border: none; background: transparent; outline: none; - font-size: 14px; + /* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */ + font-size: 16px; flex: 1; } diff --git a/frontend/src/features/seller/views/MobileSellerListingCreateView.css b/frontend/src/features/seller/views/MobileSellerListingCreateView.css index 9a9457c..75a5b9d 100644 --- a/frontend/src/features/seller/views/MobileSellerListingCreateView.css +++ b/frontend/src/features/seller/views/MobileSellerListingCreateView.css @@ -84,7 +84,8 @@ .publish-field :deep(.van-field__control) { color: #20242a; - font-size: 14px; + /* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */ + font-size: 16px; } .hint-label, diff --git a/frontend/src/styles/base.css b/frontend/src/styles/base.css index 1bbe58e..44ac404 100644 --- a/frontend/src/styles/base.css +++ b/frontend/src/styles/base.css @@ -37,6 +37,21 @@ a { text-decoration: none; } +/* + * iOS Safari 在 input/textarea/select 的 font-size < 16px 时, + * 聚焦会自动放大页面,导致 UI 被轻微放大且需手动缩小才能恢复。 + * 在触控设备上统一保证可编辑控件至少 16px。 + * 组件内若需更小视觉字号,请用 transform: scale() 等方式,不要直接用 <16px 的 font-size。 + */ +@media (hover: none) and (pointer: coarse) { + input:not([type='checkbox']):not([type='radio']):not([type='range']):not([type='file']):not([type='button']):not([type='submit']):not([type='reset']):not([type='image']), + textarea, + select, + .van-field__control { + font-size: 16px !important; + } +} + /* ── Vant Toast 保护规则 ────────────────────────────────── .van-popup 声明 background: var(--van-popup-background) = #fff (白色) .van-toast 声明 background: var(--van-toast-background) = rgba(0,0,0,.7) (黑色)