统一金额分制重构
This commit is contained in:
@@ -10,7 +10,7 @@ export interface DashboardMetrics {
|
||||
total_orders: number
|
||||
renting_orders: number
|
||||
today_orders: number
|
||||
today_ledger_amount: number
|
||||
today_ledger_amount_cent: number
|
||||
}
|
||||
|
||||
export interface DashboardPending {
|
||||
@@ -27,8 +27,8 @@ export interface DashboardRecentOrder {
|
||||
renter_id: number
|
||||
owner_id: number
|
||||
status: OrderStatus
|
||||
rent_amount: number
|
||||
deposit_amount: number
|
||||
rent_amount_cent: number
|
||||
deposit_amount_cent: number
|
||||
created_at: string
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ export interface FinanceSummary {
|
||||
total_refund_amount_cent: number
|
||||
pending_refund_amount_cent: number
|
||||
channel_net_amount_cent: number
|
||||
platform_income_amount: number
|
||||
owner_should_income_amount: number
|
||||
owner_wallet_income_amount: number
|
||||
settlement_diff_amount: number
|
||||
platform_income_amount_cent: number
|
||||
owner_should_income_amount_cent: number
|
||||
owner_wallet_income_amount_cent: number
|
||||
settlement_diff_amount_cent: number
|
||||
successful_pay_count: number
|
||||
successful_refund_count: number
|
||||
pending_refund_count: number
|
||||
@@ -23,10 +23,10 @@ export interface FinanceDailyItem {
|
||||
total_refund_amount_cent: number
|
||||
pending_refund_amount_cent: number
|
||||
channel_net_amount_cent: number
|
||||
platform_income_amount: number
|
||||
owner_should_income_amount: number
|
||||
owner_wallet_income_amount: number
|
||||
settlement_diff_amount: number
|
||||
platform_income_amount_cent: number
|
||||
owner_should_income_amount_cent: number
|
||||
owner_wallet_income_amount_cent: number
|
||||
settlement_diff_amount_cent: number
|
||||
successful_pay_count: number
|
||||
successful_refund_count: number
|
||||
pending_refund_count: number
|
||||
@@ -51,20 +51,20 @@ export interface FinanceDetail {
|
||||
owner_id: number
|
||||
owner_phone: string
|
||||
owner_nickname: string
|
||||
order_rent_amount: number
|
||||
order_deposit_amount: number
|
||||
checkout_rent_amount: number
|
||||
checkout_renter_refund: number
|
||||
checkout_owner_income: number
|
||||
checkout_platform_fee: number
|
||||
owner_wallet_income_amount: number
|
||||
order_rent_amount_cent: number
|
||||
order_deposit_amount_cent: number
|
||||
checkout_rent_amount_cent: number
|
||||
checkout_renter_refund_cent: number
|
||||
checkout_owner_income_cent: number
|
||||
checkout_platform_fee_cent: number
|
||||
owner_wallet_income_amount_cent: number
|
||||
paid_amount_cent: number
|
||||
refunded_amount_cent: number
|
||||
refunding_amount_cent: number
|
||||
failed_refund_amount_cent: number
|
||||
channel_net_amount_cent: number
|
||||
platform_net_amount: number
|
||||
settlement_diff_amount: number
|
||||
platform_net_amount_cent: number
|
||||
settlement_diff_amount_cent: number
|
||||
finance_status: string
|
||||
created_at: string
|
||||
settled_at?: string
|
||||
|
||||
@@ -10,9 +10,9 @@ export interface AdminUserItem {
|
||||
realname_status: RealnameStatusValue
|
||||
risk_status: RiskStatus
|
||||
credit_score: number
|
||||
deposit_free_quota: number
|
||||
deposit_free_used: number
|
||||
deposit_free_remaining: number
|
||||
deposit_free_quota_cent: number
|
||||
deposit_free_used_cent: number
|
||||
deposit_free_remaining_cent: number
|
||||
status: UserStatus
|
||||
order_count: number
|
||||
listing_count: number
|
||||
@@ -44,10 +44,10 @@ export async function unfreezeAdminUser(id: number) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function setAdminUserDepositFreeQuota(id: number, amount: number) {
|
||||
export async function setAdminUserDepositFreeQuota(id: number, amountCent: number) {
|
||||
const { data } = await apiClient.post<ApiResponse<AdminUserItem>>(
|
||||
`/admin/users/${id}/deposit-free-quota`,
|
||||
{ amount }
|
||||
{ amount_cent: amountCent }
|
||||
)
|
||||
return data.data
|
||||
}
|
||||
|
||||
@@ -12,9 +12,6 @@ export interface WithdrawalDetail {
|
||||
amount_cent: number
|
||||
fee_cent: number
|
||||
actual_amount_cent: number
|
||||
amount?: number
|
||||
fee?: number
|
||||
actual_amount?: number
|
||||
payment_account_id: number | null
|
||||
account_type: string
|
||||
account_name: string
|
||||
|
||||
@@ -17,12 +17,10 @@ import {
|
||||
} from '@element-plus/icons-vue'
|
||||
import { fetchAdminDashboard, type AdminDashboard } from '@/features/admin/api/adminDashboard'
|
||||
import { useAdminTable } from '@/features/admin/composables/useAdminTable'
|
||||
import { useMoney } from '@/shared/composables/useMoney'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import { disputeStatusLabel, orderStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
|
||||
const money = useMoney()
|
||||
|
||||
const {
|
||||
loading,
|
||||
error,
|
||||
@@ -98,7 +96,7 @@ const {
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<span>今日流水</span>
|
||||
<strong>{{ money(dashboard.metrics.today_ledger_amount) }}</strong>
|
||||
<strong>{{ formatCentWithSymbol(dashboard.metrics.today_ledger_amount_cent) }}</strong>
|
||||
<small>今日订单 {{ dashboard.metrics.today_orders }} 个</small>
|
||||
</div>
|
||||
</div>
|
||||
@@ -224,9 +222,9 @@ const {
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="rent_amount" label="金额" width="100">
|
||||
<el-table-column prop="rent_amount_cent" label="金额" width="100">
|
||||
<template #default="{ row }">
|
||||
<span class="amount">{{ money(row.rent_amount) }}</span>
|
||||
<span class="amount">{{ formatCentWithSymbol(row.rent_amount_cent) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" min-width="180">
|
||||
|
||||
@@ -7,6 +7,7 @@ import { fetchAdminFileBlob } from '@/shared/api/files'
|
||||
import { disputeStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatListingNo } from '@/utils/listingDisplay'
|
||||
import { yuanToCent } from '@/shared/utils/money'
|
||||
import AdminTablePagination from '../components/AdminTablePagination.vue'
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -100,7 +101,7 @@ async function handleArbitrate() {
|
||||
await arbitrateDispute(activeDispute.value.id, {
|
||||
result: result.value,
|
||||
remark: remark.value.trim(),
|
||||
amount: amount.value,
|
||||
amount_cent: amount.value ? yuanToCent(amount.value) : undefined,
|
||||
})
|
||||
ElMessage.success('仲裁结果已保存,双方已收到通知')
|
||||
activeDispute.value = null
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
type FinanceDashboard,
|
||||
type FinanceDailyItem,
|
||||
} from '@/features/admin/api/adminFinance'
|
||||
import { formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -31,11 +31,7 @@ async function loadDashboard() {
|
||||
}
|
||||
|
||||
function moneyCent(value: number) {
|
||||
return formatMoneyWithSymbol(Number(value || 0) / 100)
|
||||
}
|
||||
|
||||
function money(value: number) {
|
||||
return formatMoneyWithSymbol(value)
|
||||
return formatCentWithSymbol(value)
|
||||
}
|
||||
|
||||
function defaultStartDate() {
|
||||
@@ -53,11 +49,11 @@ function formatInputDate(date: Date) {
|
||||
}
|
||||
|
||||
function diffType(value: number) {
|
||||
return Math.abs(Number(value || 0)) >= 0.05 ? 'danger' : 'success'
|
||||
return Math.abs(Number(value || 0)) >= 5 ? 'danger' : 'success'
|
||||
}
|
||||
|
||||
function rowDiffClass(row: FinanceDailyItem) {
|
||||
return Math.abs(Number(row.settlement_diff_amount || 0)) >= 0.05 ? 'amount-danger' : ''
|
||||
return Math.abs(Number(row.settlement_diff_amount_cent || 0)) >= 5 ? 'amount-danger' : ''
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -107,17 +103,17 @@ function rowDiffClass(row: FinanceDailyItem) {
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>平台收入</span>
|
||||
<strong>{{ money(dashboard.summary.platform_income_amount) }}</strong>
|
||||
<strong>{{ moneyCent(dashboard.summary.platform_income_amount_cent) }}</strong>
|
||||
<small>{{ dashboard.summary.settled_order_count }} 个已结算订单</small>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>号主应得</span>
|
||||
<strong>{{ money(dashboard.summary.owner_should_income_amount) }}</strong>
|
||||
<strong>{{ moneyCent(dashboard.summary.owner_should_income_amount_cent) }}</strong>
|
||||
<small>结账单口径</small>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>号主实际入账</span>
|
||||
<strong>{{ money(dashboard.summary.owner_wallet_income_amount) }}</strong>
|
||||
<strong>{{ moneyCent(dashboard.summary.owner_wallet_income_amount_cent) }}</strong>
|
||||
<small>钱包流水口径</small>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
@@ -128,8 +124,8 @@ function rowDiffClass(row: FinanceDailyItem) {
|
||||
<div class="metric-card">
|
||||
<span>结算差异</span>
|
||||
<strong>
|
||||
<el-tag :type="diffType(dashboard.summary.settlement_diff_amount)">
|
||||
{{ money(dashboard.summary.settlement_diff_amount) }}
|
||||
<el-tag :type="diffType(dashboard.summary.settlement_diff_amount_cent)">
|
||||
{{ moneyCent(dashboard.summary.settlement_diff_amount_cent) }}
|
||||
</el-tag>
|
||||
</strong>
|
||||
<small>{{ dashboard.summary.financial_exception_count }} 个异常订单</small>
|
||||
@@ -148,17 +144,17 @@ function rowDiffClass(row: FinanceDailyItem) {
|
||||
<template #default="{ row }">{{ moneyCent(row.channel_net_amount_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平台收入" width="130">
|
||||
<template #default="{ row }">{{ money(row.platform_income_amount) }}</template>
|
||||
<template #default="{ row }">{{ moneyCent(row.platform_income_amount_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="号主应得" width="130">
|
||||
<template #default="{ row }">{{ money(row.owner_should_income_amount) }}</template>
|
||||
<template #default="{ row }">{{ moneyCent(row.owner_should_income_amount_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="号主入账" width="130">
|
||||
<template #default="{ row }">{{ money(row.owner_wallet_income_amount) }}</template>
|
||||
<template #default="{ row }">{{ moneyCent(row.owner_wallet_income_amount_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结算差异" width="130">
|
||||
<template #default="{ row }">
|
||||
<span :class="rowDiffClass(row)">{{ money(row.settlement_diff_amount) }}</span>
|
||||
<span :class="rowDiffClass(row)">{{ moneyCent(row.settlement_diff_amount_cent) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收款/退款/结算" min-width="170">
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
fetchFinanceDetails,
|
||||
type FinanceDetail,
|
||||
} from '@/features/admin/api/adminFinance'
|
||||
import { formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import { orderStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import AdminTablePagination from '../components/AdminTablePagination.vue'
|
||||
@@ -59,12 +59,8 @@ async function handlePageChange() {
|
||||
await loadDetails()
|
||||
}
|
||||
|
||||
function money(value: number) {
|
||||
return formatMoneyWithSymbol(value)
|
||||
}
|
||||
|
||||
function moneyCent(value: number) {
|
||||
return formatMoneyWithSymbol(Number(value || 0) / 100)
|
||||
return formatCentWithSymbol(value)
|
||||
}
|
||||
|
||||
function financeStatusLabel(status: string) {
|
||||
@@ -226,14 +222,14 @@ function formatInputDate(date: Date) {
|
||||
{{ moneyCent(row.refunding_amount_cent) }}
|
||||
</span>
|
||||
<span class="amount-text amount-cell">{{ moneyCent(row.channel_net_amount_cent) }}</span>
|
||||
<span class="amount-text amount-cell">{{ money(row.checkout_platform_fee) }}</span>
|
||||
<span class="amount-text amount-cell">{{ money(row.checkout_owner_income) }}</span>
|
||||
<span class="amount-text amount-cell">{{ money(row.owner_wallet_income_amount) }}</span>
|
||||
<span class="amount-text amount-cell">{{ moneyCent(row.checkout_platform_fee_cent) }}</span>
|
||||
<span class="amount-text amount-cell">{{ moneyCent(row.checkout_owner_income_cent) }}</span>
|
||||
<span class="amount-text amount-cell">{{ moneyCent(row.owner_wallet_income_amount_cent) }}</span>
|
||||
<span
|
||||
class="amount-text amount-cell"
|
||||
:class="{ 'amount-danger': Math.abs(row.settlement_diff_amount) >= 0.05 }"
|
||||
:class="{ 'amount-danger': Math.abs(row.settlement_diff_amount_cent) >= 5 }"
|
||||
>
|
||||
{{ money(row.settlement_diff_amount) }}
|
||||
{{ moneyCent(row.settlement_diff_amount_cent) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import { fetchAdminFileBlob } from '@/shared/api/files'
|
||||
import { formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import {
|
||||
adminMarkListingAbnormal,
|
||||
adminOfflineListing,
|
||||
@@ -78,12 +78,12 @@ async function submitAction() {
|
||||
}
|
||||
}
|
||||
|
||||
function money(value: number) {
|
||||
return formatMoneyWithSymbol(value)
|
||||
function moneyCent(value: number) {
|
||||
return formatCentWithSymbol(value)
|
||||
}
|
||||
|
||||
function listingPrice(row: Listing) {
|
||||
return money(row.price)
|
||||
return moneyCent(row.price_cent)
|
||||
}
|
||||
|
||||
function extractObjectKey(url: string) {
|
||||
@@ -150,7 +150,7 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>押金</span>
|
||||
<strong>{{ money(listing.deposit_amount) }}</strong>
|
||||
<strong>{{ moneyCent(listing.deposit_amount_cent) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -172,7 +172,7 @@ function readError(error: unknown, fallback: string) {
|
||||
<p>号主:{{ listing.owner_phone || listing.owner_nickname || listing.owner_id }}</p>
|
||||
<p>号主 ID:{{ listing.owner_id }}</p>
|
||||
<p>价格:{{ listingPrice(listing) }}</p>
|
||||
<p>押金:{{ money(listing.deposit_amount) }}</p>
|
||||
<p>押金:{{ moneyCent(listing.deposit_amount_cent) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
||||
|
||||
import { fetchAdminFileBlob } from '@/shared/api/files'
|
||||
import { formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { centToYuan, formatCent, formatMoneyWithSymbol, yuanToCent } from '@/shared/utils/money'
|
||||
import {
|
||||
adjustListingReviewPrice,
|
||||
approveListing,
|
||||
@@ -185,10 +185,10 @@ async function handleSavePriceAdjust() {
|
||||
reason: priceAdjustForm.reason.trim(),
|
||||
}
|
||||
: {
|
||||
buyer_total_price: Number(priceAdjustForm.buyer_total_price || 0),
|
||||
buyer_total_price_cent: yuanToCent(Number(priceAdjustForm.buyer_total_price || 0)),
|
||||
reason: priceAdjustForm.reason.trim(),
|
||||
}
|
||||
if ((payload.buyer_ratio || payload.buyer_total_price || 0) <= 0) {
|
||||
if ((payload.buyer_ratio || payload.buyer_total_price_cent || 0) <= 0) {
|
||||
ElMessage.warning('请填写有效的加价后比例或价格')
|
||||
return
|
||||
}
|
||||
@@ -298,8 +298,9 @@ function roundPreviewRatio(value: number) {
|
||||
function sellerTotalPrice(row: Listing) {
|
||||
const value = breakdownNumber(row, 'seller_total_price')
|
||||
if (value > 0) return value
|
||||
const fallback = Number(row.price || 0) - getListingConsumablePrice(row)
|
||||
return fallback > 0 ? fallback : Number(row.price || 0)
|
||||
const price = centToYuan(row.price_cent)
|
||||
const fallback = price - getListingConsumablePrice(row)
|
||||
return fallback > 0 ? fallback : price
|
||||
}
|
||||
|
||||
function sellerCoinBasePrice(row: Listing) {
|
||||
@@ -318,7 +319,7 @@ function sellerRatio(row: Listing) {
|
||||
|
||||
function buyerTotalPrice(row: Listing) {
|
||||
const value = breakdownNumber(row, 'buyer_total_price')
|
||||
return value > 0 ? value : Number(row.price || 0)
|
||||
return value > 0 ? value : centToYuan(row.price_cent)
|
||||
}
|
||||
|
||||
function buyerCoinBasePrice(row: Listing) {
|
||||
@@ -463,7 +464,7 @@ function riskItems(row: Listing): RiskItem[] {
|
||||
if (hasBanRecord(row)) items.push({ label: `封禁记录:${banRecordText(row)}`, level: 'danger' })
|
||||
if (
|
||||
getListingConsumablePrice(row) > 0 &&
|
||||
Number(row.deposit_amount || 0) <= getListingConsumablePrice(row)
|
||||
centToYuan(row.deposit_amount_cent) <= getListingConsumablePrice(row)
|
||||
) {
|
||||
items.push({ label: '押金不高于消耗品价值', level: 'danger' })
|
||||
}
|
||||
@@ -646,7 +647,7 @@ function readError(error: unknown, fallback: string) {
|
||||
<span>KD {{ assetNumberText(item, 'secret_kd') }}</span>
|
||||
</div>
|
||||
<div class="queue-footer">
|
||||
<span>{{ money(item.price) }} / 押 {{ money(item.deposit_amount) }}</span>
|
||||
<span>¥{{ formatCent(item.price_cent) }} / 押 ¥{{ formatCent(item.deposit_amount_cent) }}</span>
|
||||
<el-tag v-if="isExternalUpload(item)" size="small" type="info">{{
|
||||
uploaderName(item)
|
||||
}}</el-tag>
|
||||
@@ -733,7 +734,7 @@ function readError(error: unknown, fallback: string) {
|
||||
</div>
|
||||
<div class="price-decision-card deposit">
|
||||
<span>押金与损耗</span>
|
||||
<strong>{{ money(selectedListing.deposit_amount) }}</strong>
|
||||
<strong>¥{{ formatCent(selectedListing.deposit_amount_cent) }}</strong>
|
||||
<p>每日损耗 {{ dailyLossText(selectedListing) }}</p>
|
||||
<small>哈夫币 {{ formatHafCoinM(getCoinWan(selectedListing)) }}</small>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
type Listing,
|
||||
} from '@/features/listings'
|
||||
import { useAdminTable } from '@/features/admin/composables/useAdminTable'
|
||||
import { useMoney } from '@/shared/composables/useMoney'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import {
|
||||
assetRegions,
|
||||
formatEstimatedRentalDuration,
|
||||
@@ -23,8 +23,6 @@ import {
|
||||
getSkinGroup,
|
||||
} from '@/utils/listingDisplay'
|
||||
|
||||
const money = useMoney()
|
||||
|
||||
const filters = reactive<AdminListingQuery>({
|
||||
owner_id: '',
|
||||
status: '',
|
||||
@@ -322,7 +320,7 @@ function readScreenshotError(error: unknown, fallback: string) {
|
||||
}
|
||||
|
||||
function listingPrice(row: Listing) {
|
||||
return money(row.price)
|
||||
return formatCentWithSymbol(row.price_cent)
|
||||
}
|
||||
|
||||
function listingCoinM(row: Listing) {
|
||||
@@ -372,7 +370,7 @@ function characterAndWeaponSkinText(row: Listing) {
|
||||
}
|
||||
|
||||
function rentAndDepositText(row: Listing) {
|
||||
return `${listingPrice(row)}/${money(row.deposit_amount)}`
|
||||
return `${listingPrice(row)}/${formatCentWithSymbol(row.deposit_amount_cent)}`
|
||||
}
|
||||
|
||||
function estimateTitle(row: Listing) {
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
type RefundStatus,
|
||||
} from '@/features/orders'
|
||||
import { fetchAdminPayments, type AdminPayment } from '@/features/admin/api/adminPayments'
|
||||
import { centToYuan, formatMoney, formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { centToYuan, formatCentWithSymbol, formatMoney } from '@/shared/utils/money'
|
||||
import { handoffStatusLabel, orderStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatListingNo } from '@/utils/listingDisplay'
|
||||
@@ -111,9 +111,9 @@ function money(value: unknown) {
|
||||
return formatMoney(Number(value || 0))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
async function handleRefund() {
|
||||
@@ -173,7 +173,7 @@ function paymentBizTypeLabel(type: string) {
|
||||
}
|
||||
|
||||
function moneyCent(value: number) {
|
||||
return formatMoneyWithSymbol(Number(value || 0) / 100)
|
||||
return formatCentWithSymbol(value)
|
||||
}
|
||||
|
||||
function formatHandoffRecordType(type: string) {
|
||||
@@ -232,15 +232,15 @@ function formatHandoffRecordType(type: string) {
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>订单金额</span>
|
||||
<strong>¥{{ money(amountYuan(order.rent_amount_cent, order.rent_amount)) }}</strong>
|
||||
<strong>¥{{ money(amountYuan(order.rent_amount_cent)) }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>平台费用</span>
|
||||
<strong>¥{{ money(amountYuan(order.platform_fee_cent, order.platform_fee)) }}</strong>
|
||||
<strong>¥{{ money(amountYuan(order.platform_fee_cent)) }}</strong>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<span>押金</span>
|
||||
<strong>¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}</strong>
|
||||
<strong>¥{{ money(amountYuan(order.deposit_amount_cent)) }}</strong>
|
||||
</div>
|
||||
<div v-if="refundStatus" class="metric-card">
|
||||
<span>退款状态</span>
|
||||
|
||||
@@ -37,9 +37,9 @@ const filteredOrders = computed(() => {
|
||||
return orders.value.filter(item => item.status === status.value)
|
||||
})
|
||||
|
||||
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 money(value: unknown) {
|
||||
@@ -95,10 +95,10 @@ function money(value: unknown) {
|
||||
<template #default="{ row }">{{ settlementStatusLabel(row.settlement_status) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单金额" width="100">
|
||||
<template #default="{ row }">¥{{ money(amountYuan(row.rent_amount_cent, row.rent_amount)) }}</template>
|
||||
<template #default="{ row }">¥{{ money(amountYuan(row.rent_amount_cent)) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="押金" width="100">
|
||||
<template #default="{ row }">¥{{ money(amountYuan(row.deposit_amount_cent, row.deposit_amount)) }}</template>
|
||||
<template #default="{ row }">¥{{ money(amountYuan(row.deposit_amount_cent)) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" min-width="180">
|
||||
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type PaymentConfig,
|
||||
} from '@/features/admin/api/paymentConfig'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatMoney } from '@/shared/utils/money'
|
||||
import { formatCent } from '@/shared/utils/money'
|
||||
import { readError } from '@/utils/error'
|
||||
import PaymentConfigDialog from '../components/PaymentConfigDialog.vue'
|
||||
|
||||
@@ -231,7 +231,7 @@ function formatEnvironment(env: string) {
|
||||
}
|
||||
|
||||
function formatAmount(amountCent: number) {
|
||||
return formatMoney(amountCent / 100)
|
||||
return formatCent(amountCent)
|
||||
}
|
||||
|
||||
function getStatusType(status: string) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Document, Search } from '@element-plus/icons-vue'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
|
||||
import { fetchAdminPayments, type AdminPayment } from '@/features/admin/api/adminPayments'
|
||||
import { formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { formatCentWithSymbol } from '@/shared/utils/money'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import AdminTablePagination from '../components/AdminTablePagination.vue'
|
||||
|
||||
@@ -70,7 +70,7 @@ async function handlePageChange() {
|
||||
}
|
||||
|
||||
function moneyCent(value: number) {
|
||||
return formatMoneyWithSymbol(Number(value || 0) / 100)
|
||||
return formatCentWithSymbol(value)
|
||||
}
|
||||
|
||||
function paymentStatusType(status: string) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
unfreezeAdminUser,
|
||||
type AdminUserItem,
|
||||
} from '@/features/admin/api/adminUsers'
|
||||
import { formatMoney } from '@/shared/utils/money'
|
||||
import { centToYuan, formatCent, yuanToCent } from '@/shared/utils/money'
|
||||
import { useAdminPaginatedTable } from '@/features/admin/composables/useAdminPaginatedTable'
|
||||
import { userStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
@@ -39,14 +39,14 @@ function openFreeze(row: AdminUserItem) {
|
||||
|
||||
function openDepositQuota(row: AdminUserItem) {
|
||||
quotaUser.value = row
|
||||
quotaAmount.value = Number(row.deposit_free_quota || 0)
|
||||
quotaAmount.value = centToYuan(row.deposit_free_quota_cent)
|
||||
}
|
||||
|
||||
async function handleSetDepositQuota() {
|
||||
if (!quotaUser.value) return
|
||||
submitting.value = true
|
||||
try {
|
||||
await setAdminUserDepositFreeQuota(quotaUser.value.id, quotaAmount.value)
|
||||
await setAdminUserDepositFreeQuota(quotaUser.value.id, yuanToCent(quotaAmount.value))
|
||||
ElMessage.success('免押额度已更新')
|
||||
quotaUser.value = null
|
||||
await loadUsers()
|
||||
@@ -93,8 +93,8 @@ function readError(error: unknown, fallback: string) {
|
||||
return fallback
|
||||
}
|
||||
|
||||
function money(value: number | string | undefined) {
|
||||
return formatMoney(Number(value || 0))
|
||||
function moneyCent(value: number | string | undefined) {
|
||||
return formatCent(Number(value || 0))
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -117,13 +117,13 @@ function money(value: number | string | undefined) {
|
||||
<template #default="{ row }">{{ userStatusLabel(row.status) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="免押额度" width="130">
|
||||
<template #default="{ row }">¥{{ money(row.deposit_free_quota) }}</template>
|
||||
<template #default="{ row }">¥{{ moneyCent(row.deposit_free_quota_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已占用" width="120">
|
||||
<template #default="{ row }">¥{{ money(row.deposit_free_used) }}</template>
|
||||
<template #default="{ row }">¥{{ moneyCent(row.deposit_free_used_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="剩余免押" width="120">
|
||||
<template #default="{ row }">¥{{ money(row.deposit_free_remaining) }}</template>
|
||||
<template #default="{ row }">¥{{ moneyCent(row.deposit_free_remaining_cent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="注册时间" min-width="180">
|
||||
<template #default="{ row }">{{ formatDateTime(row.created_at) }}</template>
|
||||
@@ -195,8 +195,8 @@ function money(value: number | string | undefined) {
|
||||
<strong>{{ quotaUser.phone }}</strong> · {{ quotaUser.nickname }}
|
||||
</p>
|
||||
<p>
|
||||
已占用 ¥{{ money(quotaUser.deposit_free_used) }},剩余 ¥{{
|
||||
money(quotaUser.deposit_free_remaining)
|
||||
已占用 ¥{{ moneyCent(quotaUser.deposit_free_used_cent) }},剩余 ¥{{
|
||||
moneyCent(quotaUser.deposit_free_remaining_cent)
|
||||
}}
|
||||
</p>
|
||||
<el-input-number
|
||||
|
||||
@@ -47,7 +47,7 @@ export async function fetchAdminDisputes(page = 1, pageSize = 20) {
|
||||
|
||||
export async function arbitrateDispute(
|
||||
id: number,
|
||||
payload: { result: string; remark: string; amount?: number }
|
||||
payload: { result: string; remark: string; amount_cent?: number }
|
||||
) {
|
||||
const { data } = await apiClient.post<ApiResponse<Dispute>>(
|
||||
`/admin/disputes/${id}/arbitrate`,
|
||||
|
||||
@@ -19,8 +19,8 @@ export interface Listing {
|
||||
asset_summary?: Record<string, unknown>
|
||||
screenshot_urls: string[]
|
||||
cover_url: string
|
||||
price: number
|
||||
deposit_amount: number
|
||||
price_cent: number
|
||||
deposit_amount_cent: number
|
||||
is_accelerated_sale?: boolean
|
||||
in_transaction: boolean
|
||||
status: ListingStatus
|
||||
@@ -40,8 +40,8 @@ export interface ListingPayload {
|
||||
haf_coin_amount: number
|
||||
asset_summary?: Record<string, unknown>
|
||||
screenshot_urls: string[]
|
||||
price: number
|
||||
deposit_amount: number
|
||||
price_cent: number
|
||||
deposit_amount_cent: number
|
||||
agreed_virtual_asset_sale: boolean
|
||||
agreed_seller_agreement: boolean
|
||||
}
|
||||
@@ -214,7 +214,7 @@ export async function approveListing(id: number) {
|
||||
|
||||
export interface AdminListingPriceAdjustPayload {
|
||||
buyer_ratio?: number
|
||||
buyer_total_price?: number
|
||||
buyer_total_price_cent?: number
|
||||
reason?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { computed } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import type { Listing } from '@/features/listings'
|
||||
import { formatMoney } from '@/shared/utils/money'
|
||||
import { formatCent, formatMoney } from '@/shared/utils/money'
|
||||
import {
|
||||
formatHafCoinM,
|
||||
getCoinWan,
|
||||
@@ -140,7 +140,7 @@ function formatStatNumber(value: number) {
|
||||
</div>
|
||||
<div class="price-item deposit">
|
||||
<small>押金</small>
|
||||
<span>¥{{ formatMoney(listing.deposit_amount) }}</span>
|
||||
<span>¥{{ formatCent(listing.deposit_amount_cent) }}</span>
|
||||
</div>
|
||||
<div class="price-action">
|
||||
<button class="rent-btn">立即租用</button>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '@/features/orders/api/orders'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||
import { roundMoney, formatMoney } from '@/shared/utils/money'
|
||||
import { roundMoney, formatMoney, formatCent } from '@/shared/utils/money'
|
||||
import {
|
||||
assetRegions,
|
||||
formatEstimatedRentalDuration,
|
||||
@@ -102,7 +102,7 @@ const detailMetrics = computed(() => {
|
||||
tone: 'coin',
|
||||
},
|
||||
{ label: '价格', value: `¥${orderTotal.value}`, tone: 'price' },
|
||||
{ label: '押金', value: `¥${formatMoney(listing.value.deposit_amount)}`, tone: '' },
|
||||
{ label: '押金', value: `¥${formatCent(listing.value.deposit_amount_cent)}`, tone: '' },
|
||||
]
|
||||
})
|
||||
|
||||
@@ -465,7 +465,7 @@ function listingPrice(item: Listing) {
|
||||
<strong>¥{{ formatMoney(orderPriceBreakdown.consumable) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<em>押金另付 ¥{{ formatMoney(listing.deposit_amount) }}</em>
|
||||
<em>押金另付 ¥{{ formatCent(listing.deposit_amount_cent) }}</em>
|
||||
</div>
|
||||
<dl class="order-check-list">
|
||||
<div>
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
type ListingPublishOptions,
|
||||
} from '@/features/listings/api/listingOptions'
|
||||
import { fetchListings, type Listing } from '@/features/listings/api/listings'
|
||||
import { formatMoney } from '@/shared/utils/money'
|
||||
import { centToYuan, formatCent, formatMoney } from '@/shared/utils/money'
|
||||
import {
|
||||
defaultHomeAnnouncements,
|
||||
defaultHomeBanners,
|
||||
@@ -347,7 +347,7 @@ function matchesFilters(item: Listing) {
|
||||
if (key === 'price') value = getListingDisplayPrice(item)
|
||||
if (key === 'coin') value = getCoinM(item)
|
||||
if (key === 'secretKd') value = readAssetNumber(item, 'secret_kd')
|
||||
if (key === 'deposit') value = Number(item.deposit_amount || 0)
|
||||
if (key === 'deposit') value = centToYuan(item.deposit_amount_cent)
|
||||
if (key.startsWith('resource_')) {
|
||||
value = getResourceQuantity(item, key.replace('resource_', ''))
|
||||
}
|
||||
@@ -622,7 +622,7 @@ function parseQuantityUnit(price: string) {
|
||||
</div>
|
||||
<div class="resource-price-box">
|
||||
<strong>¥{{ formatMoney(getListingDisplayPrice(item)) }}</strong>
|
||||
<span class="rent-sub">押金¥{{ formatMoney(item.deposit_amount) }}</span>
|
||||
<span class="rent-sub">押金¥{{ formatCent(item.deposit_amount_cent) }}</span>
|
||||
</div>
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { showToast } from 'vant'
|
||||
import MobileBottomNav from '@/components/MobileBottomNav.vue'
|
||||
|
||||
import { ensureSupportChat } from '@/features/chats/api/chats'
|
||||
import { formatMoney } from '@/shared/utils/money'
|
||||
import { formatCent, formatMoney } from '@/shared/utils/money'
|
||||
import {
|
||||
emptyListingPublishOptions,
|
||||
type ListingPublishOptions,
|
||||
@@ -697,7 +697,7 @@ function chipTone(label: string) {
|
||||
<div class="card-footer">
|
||||
<div class="price-col">
|
||||
<strong>¥{{ formatMoney(getListingDisplayPrice(item)) }}</strong>
|
||||
<span class="rent-sub">押金 ¥{{ formatMoney(item.deposit_amount) }}</span>
|
||||
<span class="rent-sub">押金 ¥{{ formatCent(item.deposit_amount_cent) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '@/features/orders/api/orders'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
import AuthImage from '@/shared/components/business/AuthImage.vue'
|
||||
import { formatMoney } from '@/shared/utils/money'
|
||||
import { formatCent, formatMoney } from '@/shared/utils/money'
|
||||
import {
|
||||
assetRegions,
|
||||
formatHafCoinM,
|
||||
@@ -95,7 +95,7 @@ const detailMetrics = computed(() => {
|
||||
tone: 'coin',
|
||||
},
|
||||
{ label: '价格', value: `¥${formatMoney(getListingDisplayPrice(listing.value))}`, tone: 'price' },
|
||||
{ label: '押金', value: `¥${formatMoney(listing.value.deposit_amount)}`, tone: '' },
|
||||
{ label: '押金', value: `¥${formatCent(listing.value.deposit_amount_cent)}`, tone: '' },
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
writePublishDraft,
|
||||
} from '@/features/seller/composables/usePublishDraft'
|
||||
import type { PublishForm } from '@/types/publish'
|
||||
import { yuanToCent } from '@/shared/utils/money'
|
||||
import { commonOnlineTimes, dailyLossOptions, formatNumber, roundRatio } from '@/utils/pricing'
|
||||
|
||||
const draftSaveDelay = 400
|
||||
@@ -567,8 +568,8 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
haf_coin_amount: pricing.coinMAmount.value * 1000000,
|
||||
asset_summary: buildAssetSummary(),
|
||||
screenshot_urls: pricing.screenshotUrls.value,
|
||||
price: pricing.calculatedFinalPrice.value,
|
||||
deposit_amount: Number(form.deposit_amount),
|
||||
price_cent: yuanToCent(pricing.calculatedFinalPrice.value),
|
||||
deposit_amount_cent: yuanToCent(Number(form.deposit_amount)),
|
||||
agreed_virtual_asset_sale: virtualAssetSaleAgreementChecked.value,
|
||||
agreed_seller_agreement: sellerAgreementChecked.value,
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ import { fetchOrders, type Order } from '@/features/orders'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
import { handoffStatusLabel, orderStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatDateTime } from '@/utils/time'
|
||||
import { formatMoney } from '@/shared/utils/money'
|
||||
import { centToYuan, formatMoney } from '@/shared/utils/money'
|
||||
import { formatListingNo } from '@/utils/listingDisplay'
|
||||
|
||||
const session = useSessionStore()
|
||||
@@ -73,6 +73,10 @@ function actionText(order: Order) {
|
||||
function money(value: unknown) {
|
||||
return formatMoney(Number(value || 0))
|
||||
}
|
||||
|
||||
function sellerAmount(order: Order) {
|
||||
return centToYuan(order.owner_rent_amount_cent ?? order.display_amount_cent)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -122,7 +126,7 @@ function money(value: unknown) {
|
||||
<el-table-column prop="order_no" label="订单号" min-width="220" />
|
||||
<el-table-column prop="title" label="账号" min-width="180" />
|
||||
<el-table-column label="金额" width="120">
|
||||
<template #default="{ row }">¥{{ money(row.display_amount) }}</template>
|
||||
<template #default="{ row }">¥{{ money(sellerAmount(row)) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" width="150">
|
||||
<template #default="{ row }">{{ orderStatusLabel(row.status) }}</template>
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
submitListingReview,
|
||||
type Listing,
|
||||
} from '@/features/listings'
|
||||
import { formatMoney, formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { formatCent, formatMoney, formatMoneyWithSymbol } from '@/shared/utils/money'
|
||||
import { listingReviewStatusLabel, listingStatusLabel } from '@/utils/statusLabels'
|
||||
import { formatListingCode, getListingSellerPrice } from '@/utils/listingDisplay'
|
||||
|
||||
@@ -227,7 +227,7 @@ function isPendingReview(row: Listing) {
|
||||
</div>
|
||||
<div>
|
||||
<span>押金</span>
|
||||
<strong>¥{{ formatMoney(item.deposit_amount) }}</strong>
|
||||
<strong>¥{{ formatCent(item.deposit_amount_cent) }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { apiClient } from '@/shared/api/client'
|
||||
import type { ApiResponse, PaginatedResult } from '@/shared/types/types'
|
||||
import type { BalanceType, LedgerDirection, WalletStatus } from '@/shared/types/status'
|
||||
import type { PaymentOrder } from '@/features/orders/api/orders'
|
||||
import { yuanToCent } from '@/shared/utils/money'
|
||||
|
||||
export interface WalletAccount {
|
||||
user_id: number
|
||||
@@ -42,13 +43,13 @@ export async function fetchWalletLedger(page = 1, pageSize = 20) {
|
||||
}
|
||||
|
||||
export async function rechargeWallet(amountYuan: number) {
|
||||
const amount_cent = Math.round(amountYuan * 100)
|
||||
const amount_cent = yuanToCent(amountYuan)
|
||||
const { data } = await apiClient.post<ApiResponse<WalletAccount>>('/wallet/recharge', { amount_cent })
|
||||
return data.data
|
||||
}
|
||||
|
||||
export async function startWalletRechargePayment(amountYuan: number) {
|
||||
const amount_cent = Math.round(amountYuan * 100)
|
||||
const amount_cent = yuanToCent(amountYuan)
|
||||
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>('/wallet/recharge/pay', {
|
||||
amount_cent,
|
||||
})
|
||||
|
||||
@@ -402,8 +402,8 @@ function amountPrefix(direction: string) {
|
||||
<span>支付金额</span>
|
||||
<strong>{{
|
||||
activeRechargePayment
|
||||
? formatMoney(activeRechargePayment.amount_cent / 100)
|
||||
: formatMoney(devRechargeAmount)
|
||||
? formatCentWithSymbol(activeRechargePayment.amount_cent)
|
||||
: `¥${formatMoney(devRechargeAmount)}`
|
||||
}}</strong>
|
||||
</div>
|
||||
<div v-if="rechargePayURL()" class="cashier-qr">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Listing } from '@/features/listings/api/listings'
|
||||
import { centToYuan } from '@/shared/utils/money'
|
||||
|
||||
export interface ListingDisplayChip {
|
||||
label: string
|
||||
@@ -41,7 +42,7 @@ export function formatHafCoinM(amountWan: number) {
|
||||
}
|
||||
|
||||
export function getListingDisplayPrice(item: Listing) {
|
||||
return Number(item.price || 0)
|
||||
return centToYuan(item.price_cent)
|
||||
}
|
||||
|
||||
export function getListingRentPrice(item: Listing) {
|
||||
|
||||
@@ -40,12 +40,19 @@ export function centToYuan(cent: number | undefined | null): number {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分转角(四舍五入到0.1元)
|
||||
* @example centToJiao(12345) -> 123.5
|
||||
* @example centToJiao(12344) -> 123.4
|
||||
* 分转展示用元(四舍五入到0.1元)
|
||||
* @example centToDisplayYuan(12345) -> 123.5
|
||||
* @example centToDisplayYuan(12344) -> 123.4
|
||||
*/
|
||||
export function centToDisplayYuan(cent: number | undefined | null): number {
|
||||
return roundMoney(centToYuan(cent))
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 使用 centToDisplayYuan。保留导出避免旧导入立刻失效。
|
||||
*/
|
||||
export function centToJiao(cent: number | undefined | null): number {
|
||||
return Math.round(Number(cent || 0) / 10) / 10
|
||||
return centToDisplayYuan(cent)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +61,7 @@ export function centToJiao(cent: number | undefined | null): number {
|
||||
* @example formatCent(12344) -> "123.4"
|
||||
*/
|
||||
export function formatCent(cent: number | undefined | null): string {
|
||||
return centToJiao(cent).toFixed(1)
|
||||
return centToDisplayYuan(cent).toFixed(1)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Listing } from '@/features/listings/api/listings'
|
||||
import { centToYuan } from '@/shared/utils/money'
|
||||
|
||||
export interface ListingDisplayChip {
|
||||
label: string
|
||||
@@ -41,7 +42,7 @@ export function formatHafCoinM(amountWan: number) {
|
||||
}
|
||||
|
||||
export function getListingDisplayPrice(item: Listing) {
|
||||
return Number(item.price || 0)
|
||||
return centToYuan(item.price_cent)
|
||||
}
|
||||
|
||||
export function getListingRentPrice(item: Listing) {
|
||||
|
||||
Reference in New Issue
Block a user