统一金额分制重构

This commit is contained in:
yml
2026-06-09 19:04:11 +08:00
parent 87673288ef
commit 5cd3ead4bd
69 changed files with 886 additions and 1277 deletions
@@ -26,14 +26,6 @@ export interface Order {
deposit_original_amount_cent: number
deposit_waived_amount_cent: number
platform_fee_cent?: number
// Legacy yuan fields may be present from cached/older API payloads during rollout.
display_amount?: number
rent_amount?: number
owner_rent_amount?: number
deposit_amount?: number
deposit_original_amount?: number
deposit_waived_amount?: number
platform_fee?: number
account_snapshot?: Record<string, unknown>
listing_snapshot?: string
checkout_info?: string
@@ -64,16 +56,6 @@ export interface Checkout {
deposit_deduct_amount_cent: number
renter_refund_amount_cent?: number
owner_income_amount_cent?: number
display_amount?: number
rent_amount?: number
owner_rent_amount?: number
platform_fee?: number
deposit_amount?: number
consumable_amount?: number
other_amount?: number
deposit_deduct_amount?: number
renter_refund_amount?: number
owner_income_amount?: number
content: string
evidence_urls: string[]
owner_adjustment_reason: string
@@ -319,4 +301,3 @@ export async function adminRefundOrder(id: number) {
const { data } = await apiClient.post<ApiResponse<RefundStatus>>(`/admin/orders/${id}/refund`)
return data.data
}
@@ -557,26 +557,24 @@ function formatHandoffRecordType(type: string) {
return typeMap[type] || type
}
function amountYuan(cent: unknown, legacyYuan?: unknown) {
function amountYuan(cent: unknown) {
if (cent !== undefined && cent !== null) return centToYuan(readNumber(cent))
return readNumber(legacyYuan)
return 0
}
function orderRentAmount(item: Order) {
if (item.owner_id === session.userId)
return amountYuan(item.owner_rent_amount_cent, item.owner_rent_amount ?? item.display_amount)
return amountYuan(item.owner_rent_amount_cent)
if (item.renter_id === session.userId)
return amountYuan(item.rent_amount_cent, item.rent_amount ?? item.display_amount)
return amountYuan(item.display_amount_cent, item.display_amount)
return amountYuan(item.rent_amount_cent)
return amountYuan(item.display_amount_cent)
}
function ownerActualIncome(item: Order) {
if (item.owner_id !== session.userId) return null
const value = item.checkout?.owner_income_amount_cent
if (typeof value === 'number') return centToYuan(value)
return typeof item.checkout?.owner_income_amount === 'number'
? item.checkout.owner_income_amount
: null
return null
}
function quantity(value: unknown) {
@@ -596,16 +594,10 @@ function isRecord(value: unknown): value is Record<string, unknown> {
function hydrateCounterForm() {
if (!order.value?.checkout) return
const checkout = order.value.checkout
counterForm.value.consumable_amount = amountYuan(
checkout.consumable_amount_cent,
checkout.consumable_amount
)
counterForm.value.consumable_amount = amountYuan(checkout.consumable_amount_cent)
counterForm.value.coin_consumed_m = checkout.coin_consumed_m
counterForm.value.other_amount = amountYuan(checkout.other_amount_cent, checkout.other_amount)
counterForm.value.deposit_deduct_amount = amountYuan(
checkout.deposit_deduct_amount_cent,
checkout.deposit_deduct_amount
)
counterForm.value.other_amount = amountYuan(checkout.other_amount_cent)
counterForm.value.deposit_deduct_amount = amountYuan(checkout.deposit_deduct_amount_cent)
}
function linesToList(value: string) {
@@ -696,14 +688,12 @@ async function copyListingCode() {
<div class="meta-item">
<span class="meta-label">押金</span>
<strong class="meta-value"
>¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}</strong
>¥{{ money(amountYuan(order.deposit_amount_cent)) }}</strong
>
<span
v-if="amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount) > 0"
v-if="amountYuan(order.deposit_waived_amount_cent) > 0"
class="meta-note"
>已免押 ¥{{
money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount))
}}</span
>已免押 ¥{{ money(amountYuan(order.deposit_waived_amount_cent)) }}</span
>
</div>
<div class="meta-item">
@@ -956,59 +946,36 @@ async function copyListingCode() {
<van-cell-group inset :border="false">
<van-cell
title="实际结算租金"
:value="`¥${money(
amountYuan(order.checkout.display_amount_cent, order.checkout.display_amount)
)}`"
:value="`¥${money(amountYuan(order.checkout.display_amount_cent))}`"
/>
<van-cell
title="押金总额"
:label="
amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount) > 0
? `已免押 ¥${money(
amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount)
)}`
amountYuan(order.deposit_waived_amount_cent) > 0
? `已免押 ¥${money(amountYuan(order.deposit_waived_amount_cent))}`
: ''
"
:value="`¥${money(
amountYuan(order.checkout.deposit_amount_cent, order.checkout.deposit_amount)
)}`"
:value="`¥${money(amountYuan(order.checkout.deposit_amount_cent))}`"
/>
<van-cell
title="额外消耗品已用"
:value="`¥${money(
amountYuan(order.checkout.consumable_amount_cent, order.checkout.consumable_amount)
)}`"
:value="`¥${money(amountYuan(order.checkout.consumable_amount_cent))}`"
/>
<van-cell
title="押金赔付扣除"
:value="`¥${money(
amountYuan(
order.checkout.deposit_deduct_amount_cent,
order.checkout.deposit_deduct_amount
)
)}`"
:value="`¥${money(amountYuan(order.checkout.deposit_deduct_amount_cent))}`"
value-class="red-text"
/>
<van-cell
v-if="isRenter"
title="退还租客"
:value="`¥${money(
amountYuan(
order.checkout.renter_refund_amount_cent,
order.checkout.renter_refund_amount
)
)}`"
:value="`¥${money(amountYuan(order.checkout.renter_refund_amount_cent))}`"
value-class="green-text"
/>
<van-cell
v-if="isOwner"
title="号主最终收入"
:value="`¥${money(
amountYuan(
order.checkout.owner_income_amount_cent,
order.checkout.owner_income_amount
)
)}`"
:value="`¥${money(amountYuan(order.checkout.owner_income_amount_cent))}`"
value-class="green-text"
/>
<van-cell
@@ -131,21 +131,21 @@ function amountLabel(order: Order) {
return isOwner(order) ? '预计租金' : '支付租金'
}
function amountYuan(cent: unknown, legacyYuan?: unknown) {
function amountYuan(cent: unknown) {
if (cent !== undefined && cent !== null) return centToYuan(Number(cent || 0))
return Number(legacyYuan || 0)
return 0
}
function orderRentAmount(order: Order) {
if (isOwner(order)) return amountYuan(order.owner_rent_amount_cent, order.owner_rent_amount ?? order.display_amount)
return amountYuan(order.rent_amount_cent, order.rent_amount ?? order.display_amount)
if (isOwner(order)) return amountYuan(order.owner_rent_amount_cent)
return amountYuan(order.rent_amount_cent)
}
function ownerActualIncome(order: Order) {
if (!isOwner(order)) return null
const value = order.checkout?.owner_income_amount_cent
if (typeof value === 'number') return centToYuan(value)
return typeof order.checkout?.owner_income_amount === 'number' ? order.checkout.owner_income_amount : null
return null
}
function formatListingCode(order: Order) {
@@ -238,9 +238,9 @@ async function copyListingCode(order: Order) {
<div class="price-item">
<span class="price-label">押金金额</span>
<span class="price-val deposit">
¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}
<em v-if="amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount) > 0"
>免 ¥{{ money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount)) }}</em
¥{{ money(amountYuan(order.deposit_amount_cent)) }}
<em v-if="amountYuan(order.deposit_waived_amount_cent) > 0"
>免 ¥{{ money(amountYuan(order.deposit_waived_amount_cent)) }}</em
>
</span>
</div>
@@ -8,7 +8,7 @@ import QRCode from 'qrcode'
import { fetchOrderChat } from '@/features/chats/api/chats'
import { createDispute } from '@/features/disputes'
import { uploadFile } from '@/shared/api/files'
import { centToYuan, formatMoney } from '@/shared/utils/money'
import { centToYuan, formatCent, formatMoney } from '@/shared/utils/money'
import {
acceptCheckout,
cancelOrder,
@@ -606,26 +606,24 @@ function money(value: unknown) {
return formatMoney(readNumber(value))
}
function amountYuan(cent: unknown, legacyYuan?: unknown) {
function amountYuan(cent: unknown) {
if (cent !== undefined && cent !== null) return centToYuan(readNumber(cent))
return readNumber(legacyYuan)
return 0
}
function orderRentAmount(item: Order) {
if (item.owner_id === session.userId)
return amountYuan(item.owner_rent_amount_cent, item.owner_rent_amount ?? item.display_amount)
return amountYuan(item.owner_rent_amount_cent)
if (item.renter_id === session.userId)
return amountYuan(item.rent_amount_cent, item.rent_amount ?? item.display_amount)
return amountYuan(item.display_amount_cent, item.display_amount)
return amountYuan(item.rent_amount_cent)
return amountYuan(item.display_amount_cent)
}
function ownerActualIncome(item: Order) {
if (item.owner_id !== session.userId) return null
const value = item.checkout?.owner_income_amount_cent
if (typeof value === 'number') return centToYuan(value)
return typeof item.checkout?.owner_income_amount === 'number'
? item.checkout.owner_income_amount
: null
return null
}
function quantity(value: unknown) {
@@ -645,16 +643,10 @@ function isRecord(value: unknown): value is Record<string, unknown> {
function hydrateCounterForm() {
if (!order.value?.checkout) return
const checkout = order.value.checkout
counterForm.value.consumable_amount = amountYuan(
checkout.consumable_amount_cent,
checkout.consumable_amount
)
counterForm.value.consumable_amount = amountYuan(checkout.consumable_amount_cent)
counterForm.value.coin_consumed_m = checkout.coin_consumed_m
counterForm.value.other_amount = amountYuan(checkout.other_amount_cent, checkout.other_amount)
counterForm.value.deposit_deduct_amount = amountYuan(
checkout.deposit_deduct_amount_cent,
checkout.deposit_deduct_amount
)
counterForm.value.other_amount = amountYuan(checkout.other_amount_cent)
counterForm.value.deposit_deduct_amount = amountYuan(checkout.deposit_deduct_amount_cent)
}
function linesToList(value: string) {
@@ -789,13 +781,13 @@ async function copyListingCode() {
<div class="metric-card">
<span class="metric-label">押金</span>
<strong class="metric-value"
>¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}</strong
>¥{{ money(amountYuan(order.deposit_amount_cent)) }}</strong
>
<span
v-if="amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount) > 0"
v-if="amountYuan(order.deposit_waived_amount_cent) > 0"
class="metric-note"
>已免押 ¥{{
money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount))
money(amountYuan(order.deposit_waived_amount_cent))
}}</span
>
</div>
@@ -979,81 +971,40 @@ async function copyListingCode() {
<div class="summary-row">
<span>实际结算租金</span>
<strong
>¥{{
money(
amountYuan(order.checkout.display_amount_cent, order.checkout.display_amount)
)
}}</strong
>¥{{ money(amountYuan(order.checkout.display_amount_cent)) }}</strong
>
</div>
<div class="summary-row">
<span>预收押金</span>
<strong>
¥{{
money(
amountYuan(order.checkout.deposit_amount_cent, order.checkout.deposit_amount)
)
}}
<em
v-if="
amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount) > 0
"
>已免押 ¥{{
money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount))
}}</em
¥{{ money(amountYuan(order.checkout.deposit_amount_cent)) }}
<em v-if="amountYuan(order.deposit_waived_amount_cent) > 0"
>已免押 ¥{{ money(amountYuan(order.deposit_waived_amount_cent)) }}</em
>
</strong>
</div>
<div class="summary-row">
<span>额外消耗品已用</span>
<strong class="warning"
>¥{{
money(
amountYuan(
order.checkout.consumable_amount_cent,
order.checkout.consumable_amount
)
)
}}</strong
>¥{{ money(amountYuan(order.checkout.consumable_amount_cent)) }}</strong
>
</div>
<div class="summary-row">
<span>押金赔付扣除</span>
<strong class="warning"
>¥{{
money(
amountYuan(
order.checkout.deposit_deduct_amount_cent,
order.checkout.deposit_deduct_amount
)
)
}}</strong
>¥{{ money(amountYuan(order.checkout.deposit_deduct_amount_cent)) }}</strong
>
</div>
<div v-if="isRenter" class="summary-row highlight">
<span>退还租客(未使用租金 + 剩余押金)</span>
<strong class="amount"
>¥{{
money(
amountYuan(
order.checkout.renter_refund_amount_cent,
order.checkout.renter_refund_amount
)
)
}}</strong
>¥{{ money(amountYuan(order.checkout.renter_refund_amount_cent)) }}</strong
>
</div>
<div v-if="isOwner" class="summary-row highlight">
<span>号主最终收入(租金 + 押金赔付)</span>
<strong class="amount"
>¥{{
money(
amountYuan(
order.checkout.owner_income_amount_cent,
order.checkout.owner_income_amount
)
)
}}</strong
>¥{{ money(amountYuan(order.checkout.owner_income_amount_cent)) }}</strong
>
</div>
<div v-if="order.checkout.content" class="summary-note">
@@ -1109,7 +1060,7 @@ async function copyListingCode() {
v-model="counterForm.deposit_deduct_amount"
class="full-control"
:min="0"
:max="amountYuan(order.deposit_amount_cent, order.deposit_amount)"
:max="amountYuan(order.deposit_amount_cent)"
:precision="0"
controls-position="right"
/>
@@ -1331,7 +1282,7 @@ async function copyListingCode() {
<div class="pay-summary">
<div class="pay-summary-row">
<span>支付金额</span>
<strong>¥{{ formatMoney(activePayment.amount_cent / 100) }}</strong>
<strong>¥{{ formatCent(activePayment.amount_cent) }}</strong>
</div>
</div>
<div v-if="paymentPayURL()" class="pay-qr-section">
@@ -127,22 +127,22 @@ function amountLabel(order: Order) {
return isRenter(order) ? '支付租金' : '预计租金'
}
function amountYuan(cent: unknown, legacyYuan?: unknown) {
function amountYuan(cent: unknown) {
if (cent !== undefined && cent !== null) return centToYuan(Number(cent || 0))
return Number(legacyYuan || 0)
return 0
}
function orderRentAmount(order: Order) {
if (isOwner(order)) return amountYuan(order.owner_rent_amount_cent, order.owner_rent_amount ?? order.display_amount)
if (isRenter(order)) return amountYuan(order.rent_amount_cent, order.rent_amount ?? order.display_amount)
return amountYuan(order.display_amount_cent, order.display_amount)
if (isOwner(order)) return amountYuan(order.owner_rent_amount_cent)
if (isRenter(order)) return amountYuan(order.rent_amount_cent)
return amountYuan(order.display_amount_cent)
}
function ownerActualIncome(order: Order) {
if (!isOwner(order)) return null
const value = order.checkout?.owner_income_amount_cent
if (typeof value === 'number') return centToYuan(value)
return typeof order.checkout?.owner_income_amount === 'number' ? order.checkout.owner_income_amount : null
return null
}
function money(value: unknown) {
@@ -269,9 +269,9 @@ function getCountdownMinutes(order: Order) {
<el-table-column label="押金" width="100">
<template #default="{ row }">
<div class="amount-cell">
<span class="amount-value">¥{{ money(row.deposit_amount) }}</span>
<span v-if="row.deposit_waived_amount > 0" class="amount-label"
>免 ¥{{ money(row.deposit_waived_amount) }}</span
<span class="amount-value">¥{{ money(amountYuan(row.deposit_amount_cent)) }}</span>
<span v-if="amountYuan(row.deposit_waived_amount_cent) > 0" class="amount-label"
>免 ¥{{ money(amountYuan(row.deposit_waived_amount_cent)) }}</span
>
</div>
</template>
@@ -357,9 +357,9 @@ function getCountdownMinutes(order: Order) {
<div class="meta-row">
<span class="meta-label">押金</span>
<span class="meta-value">
¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}
<em v-if="amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount) > 0"
>免 ¥{{ money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount)) }}</em
¥{{ money(amountYuan(order.deposit_amount_cent)) }}
<em v-if="amountYuan(order.deposit_waived_amount_cent) > 0"
>免 ¥{{ money(amountYuan(order.deposit_waived_amount_cent)) }}</em
>
</span>
</div>