修复移动端输入聚焦放大,并补全商品详情价格拆分
- 触控设备输入框字号至少 16px,避免 iOS Safari 聚焦自动放大 - 商品管理详情「号主与价格」对齐订单资金拆分字段展示
This commit is contained in:
@@ -9,7 +9,11 @@ import { fetchAdminUsers, type AdminUserItem } from '@/features/admin/api/adminU
|
|||||||
import { fetchAdminFileBlob } from '@/shared/api/files'
|
import { fetchAdminFileBlob } from '@/shared/api/files'
|
||||||
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||||
import { adminPath } from '@/shared/utils/adminPath'
|
import { adminPath } from '@/shared/utils/adminPath'
|
||||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
import {
|
||||||
|
formatCentWithSymbol,
|
||||||
|
formatMoneyWithSymbol,
|
||||||
|
roundMoney,
|
||||||
|
} from '@/shared/utils/money'
|
||||||
import {
|
import {
|
||||||
adminMarkListingAbnormal,
|
adminMarkListingAbnormal,
|
||||||
adminOfflineListing,
|
adminOfflineListing,
|
||||||
@@ -31,7 +35,9 @@ import {
|
|||||||
getCoinWan,
|
getCoinWan,
|
||||||
getDailyLoss,
|
getDailyLoss,
|
||||||
getListingConsumablePrice,
|
getListingConsumablePrice,
|
||||||
|
getListingDisplayPrice,
|
||||||
getListingResources,
|
getListingResources,
|
||||||
|
getListingSellerPrice,
|
||||||
getOnlineTimeText,
|
getOnlineTimeText,
|
||||||
getResourceQuantity,
|
getResourceQuantity,
|
||||||
getSkinNames,
|
getSkinNames,
|
||||||
@@ -88,21 +94,28 @@ const assetRows = computed(() => {
|
|||||||
})
|
})
|
||||||
const ownerRows = computed(() => {
|
const ownerRows = computed(() => {
|
||||||
if (!listing.value) return []
|
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 [
|
return [
|
||||||
{
|
{
|
||||||
label: '号主',
|
label: '号主',
|
||||||
value: listing.value.owner_phone || listing.value.owner_nickname || listing.value.owner_id,
|
value: row.owner_phone || row.owner_nickname || row.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)),
|
|
||||||
},
|
},
|
||||||
|
{ 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(() => {
|
const resourceCards = computed(() => {
|
||||||
@@ -240,8 +253,56 @@ function moneyCent(value: number) {
|
|||||||
return formatCentWithSymbol(value)
|
return formatCentWithSymbol(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moneyYuan(value: number) {
|
||||||
|
return formatMoneyWithSymbol(value)
|
||||||
|
}
|
||||||
|
|
||||||
function listingPrice(row: Listing) {
|
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<string, unknown>)
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
function assetText(row: Listing, key: string) {
|
||||||
|
|||||||
@@ -464,7 +464,8 @@ function sectionTopInBody(section: HTMLElement, body: HTMLElement) {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: #333;
|
color: #333;
|
||||||
font-size: 13px;
|
/* iOS Safari:font-size < 16px 时聚焦会自动放大页面,需手动缩小才能恢复 */
|
||||||
|
font-size: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home-search :deep(.van-field__control) {
|
.home-search :deep(.van-field__control) {
|
||||||
font-size: 14px;
|
/* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-service {
|
.mobile-service {
|
||||||
|
|||||||
@@ -634,7 +634,8 @@ function updateNumberField(field: 'coin_consumed_m' | 'otherAmountYuan', event:
|
|||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
font-size: 14px;
|
/* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */
|
||||||
|
font-size: 16px;
|
||||||
color: #182232;
|
color: #182232;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -821,7 +821,8 @@ async function copyListingCode() {
|
|||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
outline: none;
|
outline: none;
|
||||||
font-size: 14px;
|
/* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */
|
||||||
|
font-size: 16px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,8 @@
|
|||||||
|
|
||||||
.publish-field :deep(.van-field__control) {
|
.publish-field :deep(.van-field__control) {
|
||||||
color: #20242a;
|
color: #20242a;
|
||||||
font-size: 14px;
|
/* iOS Safari:font-size < 16px 时聚焦会自动放大页面 */
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hint-label,
|
.hint-label,
|
||||||
|
|||||||
@@ -37,6 +37,21 @@ a {
|
|||||||
text-decoration: none;
|
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 保护规则 ──────────────────────────────────
|
/* ── Vant Toast 保护规则 ──────────────────────────────────
|
||||||
.van-popup 声明 background: var(--van-popup-background) = #fff (白色)
|
.van-popup 声明 background: var(--van-popup-background) = #fff (白色)
|
||||||
.van-toast 声明 background: var(--van-toast-background) = rgba(0,0,0,.7) (黑色)
|
.van-toast 声明 background: var(--van-toast-background) = rgba(0,0,0,.7) (黑色)
|
||||||
|
|||||||
Reference in New Issue
Block a user