diff --git a/frontend/src/features/admin/api/adminWallet.ts b/frontend/src/features/admin/api/adminWallet.ts
index 5e1ab7d..69b14f8 100644
--- a/frontend/src/features/admin/api/adminWallet.ts
+++ b/frontend/src/features/admin/api/adminWallet.ts
@@ -12,8 +12,8 @@ export interface AdminWalletLedger {
order_id?: number
order_no: string
direction: LedgerDirection
- amount: number
- balance_after: number
+ amount_cent: number
+ balance_after_cent: number
balance_type: BalanceType
biz_type: string
biz_no: string
diff --git a/frontend/src/features/admin/api/adminWithdrawal.ts b/frontend/src/features/admin/api/adminWithdrawal.ts
index 9319bab..14e72e9 100644
--- a/frontend/src/features/admin/api/adminWithdrawal.ts
+++ b/frontend/src/features/admin/api/adminWithdrawal.ts
@@ -9,9 +9,12 @@ export interface WithdrawalDetail {
user_id: number
user_nickname: string
user_phone: string
- amount: number
- fee: number
- actual_amount: number
+ 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
diff --git a/frontend/src/features/admin/components/WithdrawalDetailDialog.vue b/frontend/src/features/admin/components/WithdrawalDetailDialog.vue
index eddb476..e82f1a6 100644
--- a/frontend/src/features/admin/components/WithdrawalDetailDialog.vue
+++ b/frontend/src/features/admin/components/WithdrawalDetailDialog.vue
@@ -4,7 +4,7 @@ import { ref } from 'vue'
import type { WithdrawalDetail } from '@/features/admin/api/adminWithdrawal'
import { reviewWithdrawal, confirmPayment } from '@/features/admin/api/adminWithdrawal'
-import { formatMoney } from '@/shared/utils/money'
+import { formatCent } from '@/shared/utils/money'
const props = defineProps<{
modelValue: boolean
@@ -161,15 +161,15 @@ function accountTypeLabel(type: string) {
- ¥{{ formatMoney(withdrawal.amount) }}
+ ¥{{ formatCent(withdrawal.amount_cent) }}
- ¥{{ formatMoney(withdrawal.fee) }}
+ ¥{{ formatCent(withdrawal.fee_cent) }}
- ¥{{ formatMoney(withdrawal.actual_amount) }}
+ ¥{{ formatCent(withdrawal.actual_amount_cent) }}
@@ -274,7 +274,7 @@ function accountTypeLabel(type: string) {
>
- 请手动转账 ¥{{ formatMoney(withdrawal.actual_amount) }} 到用户收款账号,
+ 请手动转账 ¥{{ formatCent(withdrawal.actual_amount_cent) }} 到用户收款账号,
完成后点击"确认打款"按钮。
diff --git a/frontend/src/features/admin/views/AdminOrderDetailView.vue b/frontend/src/features/admin/views/AdminOrderDetailView.vue
index 4b55363..7ce9b99 100644
--- a/frontend/src/features/admin/views/AdminOrderDetailView.vue
+++ b/frontend/src/features/admin/views/AdminOrderDetailView.vue
@@ -15,7 +15,7 @@ import {
type RefundStatus,
} from '@/features/orders'
import { fetchAdminPayments, type AdminPayment } from '@/features/admin/api/adminPayments'
-import { formatMoney, formatMoneyWithSymbol } from '@/shared/utils/money'
+import { centToYuan, formatMoney, formatMoneyWithSymbol } from '@/shared/utils/money'
import { handoffStatusLabel, orderStatusLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
import { formatListingNo } from '@/utils/listingDisplay'
@@ -111,6 +111,11 @@ function money(value: unknown) {
return formatMoney(Number(value || 0))
}
+function amountYuan(cent: unknown, legacyYuan?: unknown) {
+ if (cent !== undefined && cent !== null) return centToYuan(Number(cent || 0))
+ return Number(legacyYuan || 0)
+}
+
async function handleRefund() {
if (!order.value) return
refunding.value = true
@@ -227,15 +232,15 @@ function formatHandoffRecordType(type: string) {
订单金额
- ¥{{ money(order.rent_amount) }}
+ ¥{{ money(amountYuan(order.rent_amount_cent, order.rent_amount)) }}
平台费用
- ¥{{ money(order.platform_fee) }}
+ ¥{{ money(amountYuan(order.platform_fee_cent, order.platform_fee)) }}
押金
- ¥{{ money(order.deposit_amount) }}
+ ¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}
退款状态
diff --git a/frontend/src/features/admin/views/AdminOrdersView.vue b/frontend/src/features/admin/views/AdminOrdersView.vue
index a330a51..2ddd0ba 100644
--- a/frontend/src/features/admin/views/AdminOrdersView.vue
+++ b/frontend/src/features/admin/views/AdminOrdersView.vue
@@ -4,6 +4,7 @@ import { computed, onMounted, ref } from 'vue'
import { fetchAdminOrders, type Order } from '@/features/orders'
import { handoffStatusLabel, orderStatusLabel, settlementStatusLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
+import { centToYuan, formatMoney } from '@/shared/utils/money'
import { formatListingNo } from '@/utils/listingDisplay'
import AdminTablePagination from '../components/AdminTablePagination.vue'
@@ -35,6 +36,15 @@ const filteredOrders = computed(() => {
if (!status.value) return orders.value
return orders.value.filter(item => item.status === status.value)
})
+
+function amountYuan(cent: unknown, legacyYuan?: unknown) {
+ if (cent !== undefined && cent !== null) return centToYuan(Number(cent || 0))
+ return Number(legacyYuan || 0)
+}
+
+function money(value: unknown) {
+ return formatMoney(Number(value || 0))
+}
@@ -84,8 +94,12 @@ const filteredOrders = computed(() => {
{{ settlementStatusLabel(row.settlement_status) }}
-
-
+
+ ¥{{ money(amountYuan(row.rent_amount_cent, row.rent_amount)) }}
+
+
+ ¥{{ money(amountYuan(row.deposit_amount_cent, row.deposit_amount)) }}
+
{{ formatDateTime(row.created_at) }}
diff --git a/frontend/src/features/admin/views/AdminWalletLedgerView.vue b/frontend/src/features/admin/views/AdminWalletLedgerView.vue
index a657b55..5c3b68f 100644
--- a/frontend/src/features/admin/views/AdminWalletLedgerView.vue
+++ b/frontend/src/features/admin/views/AdminWalletLedgerView.vue
@@ -3,7 +3,7 @@ import { Search } from '@element-plus/icons-vue'
import { computed, onMounted, reactive, ref } from 'vue'
import { fetchAdminWalletLedger, type AdminWalletLedger } from '@/features/admin/api/adminWallet'
-import { formatMoneyWithSymbol } from '@/shared/utils/money'
+import { formatCentWithSymbol } from '@/shared/utils/money'
import { balanceTypeLabel, ledgerDirectionLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
import AdminTablePagination from '../components/AdminTablePagination.vue'
@@ -22,12 +22,12 @@ const filters = reactive({
const inAmount = computed(() =>
ledger.value
.filter(item => item.direction === 'in')
- .reduce((sum, item) => sum + Number(item.amount || 0), 0)
+ .reduce((sum, item) => sum + Number(item.amount_cent || 0), 0)
)
const outAmount = computed(() =>
ledger.value
.filter(item => item.direction === 'out')
- .reduce((sum, item) => sum + Number(item.amount || 0), 0)
+ .reduce((sum, item) => sum + Number(item.amount_cent || 0), 0)
)
onMounted(loadLedger)
@@ -65,7 +65,7 @@ async function handlePageChange() {
}
function money(value: number) {
- return formatMoneyWithSymbol(value)
+ return formatCentWithSymbol(value)
}
function directionType(direction: string) {
@@ -149,13 +149,13 @@ function directionLabel(direction: string) {
- {{ money(Number(row.amount)) }}
+ {{ money(Number(row.amount_cent)) }}
{{ balanceTypeLabel(row.balance_type) }}
- {{ money(Number(row.balance_after)) }}
+ {{ money(Number(row.balance_after_cent)) }}
{{ formatDateTime(row.created_at) }}
diff --git a/frontend/src/features/admin/views/AdminWithdrawalsView.vue b/frontend/src/features/admin/views/AdminWithdrawalsView.vue
index 25bb8de..23145e1 100644
--- a/frontend/src/features/admin/views/AdminWithdrawalsView.vue
+++ b/frontend/src/features/admin/views/AdminWithdrawalsView.vue
@@ -8,7 +8,7 @@ import {
confirmPayment,
type WithdrawalDetail,
} from '@/features/admin/api/adminWithdrawal'
-import { formatMoney } from '@/shared/utils/money'
+import { formatCent } from '@/shared/utils/money'
import WithdrawalDetailDialog from '../components/WithdrawalDetailDialog.vue'
@@ -220,7 +220,7 @@ function onDetailDialogSaved() {
- ¥{{ formatMoney(row.amount) }}
+ ¥{{ formatCent(row.amount_cent) }}
diff --git a/frontend/src/features/auth/views/MobileProfileView.vue b/frontend/src/features/auth/views/MobileProfileView.vue
index c2a1b89..9d5ecdd 100644
--- a/frontend/src/features/auth/views/MobileProfileView.vue
+++ b/frontend/src/features/auth/views/MobileProfileView.vue
@@ -13,7 +13,7 @@ import {
import { fetchPostRentalNotice, type PostRentalNotice } from '@/features/orders/api/orders'
import { formatDateMinute } from '@/utils/time'
import { uploadFile } from '@/shared/api/files'
-import { formatMoney } from '@/shared/utils/money'
+import { formatCent, formatMoney } from '@/shared/utils/money'
const session = useSessionStore()
const router = useRouter()
@@ -101,7 +101,7 @@ onMounted(() => {
async function loadBalance() {
try {
const wallet = await fetchWalletBalance()
- balance.value = wallet.available_balance
+ balance.value = wallet.available_balance_cent
} catch {
// 失败静默处理,显示为默认0
}
@@ -418,7 +418,7 @@ function resolveAvatarURL(url: string | undefined | null) {
{{ formatDateMinute(item.created_at) }}
- {{ item.direction === 'in' ? '+' : '-' }}¥{{ formatMoney(item.amount) }}
+ {{ item.direction === 'in' ? '+' : '-' }}¥{{ formatCent(item.amount_cent) }}
diff --git a/frontend/src/features/orders/api/orders.ts b/frontend/src/features/orders/api/orders.ts
index c998cea..b6790e7 100644
--- a/frontend/src/features/orders/api/orders.ts
+++ b/frontend/src/features/orders/api/orders.ts
@@ -1,6 +1,7 @@
import { apiClient } from '@/shared/api/client'
-import type { ApiResponse } from '@/shared/types/types'
+import type { ApiResponse, PaginatedResult } from '@/shared/types/types'
import type { HandoffStatus, OrderStatus, SettlementStatus } from '@/shared/types/status'
+import { yuanToCent } from '@/shared/utils/money'
export interface Order {
id: number
@@ -25,6 +26,14 @@ 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
listing_snapshot?: string
checkout_info?: string
@@ -55,6 +64,16 @@ 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
@@ -98,13 +117,77 @@ export interface PaymentOrder {
updated_at: string
}
-// API functions below remain the same, TypeScript will catch any mismatches
+export interface OrderAgreements {
+ virtual_asset_purchase: { title: string; content: string }
+ renter_agreement: { title: string; content: string }
+}
+
+export interface PostRentalNotice {
+ title: string
+ content: string
+}
+
+export interface SubmitCheckoutPayload {
+ content: string
+ consumable_amount?: number
+ coin_consumed_m: number
+ other_amount?: number
+ deposit_deduct_amount?: number
+ evidence_urls: string[]
+ reason?: string
+}
+
+interface SubmitCheckoutRequest {
+ content: string
+ consumable_amount_cent?: number
+ coin_consumed_m: number
+ other_amount_cent?: number
+ deposit_deduct_amount_cent?: number
+ evidence_urls: string[]
+ reason?: string
+}
+
+export interface StartOrderPaymentRequest {
+ pay_way?: string
+ jspay_flag?: string
+}
+
+export interface RefundStatus {
+ order_id: number
+ refund_status: string
+ refund_amount_cent: number
+ refund_no?: string
+ refunded_at?: string
+}
+
+function toCheckoutRequest(payload: SubmitCheckoutPayload): SubmitCheckoutRequest {
+ return {
+ content: payload.content,
+ consumable_amount_cent: yuanToCent(payload.consumable_amount),
+ coin_consumed_m: payload.coin_consumed_m,
+ other_amount_cent: yuanToCent(payload.other_amount),
+ deposit_deduct_amount_cent: yuanToCent(payload.deposit_deduct_amount),
+ evidence_urls: payload.evidence_urls,
+ reason: payload.reason,
+ }
+}
+
+export async function fetchOrderAgreements() {
+ const { data } = await apiClient.get>('/order-agreements')
+ return data.data
+}
+
+export async function fetchPostRentalNotice() {
+ const { data } = await apiClient.get>('/post-rental-notice')
+ return data.data
+}
+
export async function fetchOrders() {
const { data } = await apiClient.get>('/orders')
return data.data
}
-export async function fetchOrder(id: number) {
+export async function fetchOrder(id: string | number) {
const { data } = await apiClient.get>(`/orders/${id}`)
return data.data
}
@@ -119,16 +202,8 @@ export async function cancelOrder(id: number) {
return data.data
}
-export async function startPayment(orderId: number, payWay: string, jsPayFlag?: string) {
- const { data } = await apiClient.post>(`/orders/${orderId}/pay`, {
- pay_way: payWay,
- jspay_flag: jsPayFlag || '',
- })
- return data.data
-}
-
-export async function queryPayment(orderId: number) {
- const { data } = await apiClient.post>(`/orders/${orderId}/pay/query`)
+export async function submitHandoff(id: number, content: string) {
+ const { data } = await apiClient.post>(`/orders/${id}/handoffs`, { content })
return data.data
}
@@ -140,32 +215,108 @@ export async function confirmHandoff(orderId: number, type: string, content: str
return data.data
}
-export async function createCheckout(
- orderId: number,
- payload: {
- consumable_amount: number
- coin_consumed_m: number
- other_amount: number
- deposit_deduct_amount: number
- content: string
- evidence_urls: string[]
- }
-) {
- const { data } = await apiClient.post>(`/orders/${orderId}/checkout`, payload)
+export async function fetchHandoffRecords(id: string | number) {
+ const { data } = await apiClient.get>(`/orders/${id}/handoffs`)
return data.data
}
-export async function acceptCheckout(orderId: number) {
- const { data } = await apiClient.post>(`/orders/${orderId}/checkout/accept`)
+export async function confirmReceive(id: number) {
+ const { data } = await apiClient.post>(`/orders/${id}/receive`)
return data.data
}
-export async function rejectCheckout(orderId: number) {
- const { data } = await apiClient.post>(`/orders/${orderId}/checkout/reject`)
+export async function startOrderPayment(orderId: number, req: StartOrderPaymentRequest = {}) {
+ const { data } = await apiClient.post>(`/orders/${orderId}/pay`, {
+ pay_way: req.pay_way || 'wechat',
+ jspay_flag: req.jspay_flag || '',
+ })
return data.data
}
-export async function counterCheckout(orderId: number, checkoutId: number) {
- const { data } = await apiClient.post>(`/orders/${orderId}/checkout/${checkoutId}/counter`)
+export function startPayment(orderId: number, payWay: string, jsPayFlag?: string) {
+ return startOrderPayment(orderId, { pay_way: payWay, jspay_flag: jsPayFlag || '' })
+}
+
+export async function queryOrderPayment(orderId: number) {
+ const { data } = await apiClient.post>(`/orders/${orderId}/pay/query`)
return data.data
}
+
+export function queryPayment(orderId: number) {
+ return queryOrderPayment(orderId)
+}
+
+export async function submitCheckout(id: number, payload: SubmitCheckoutPayload) {
+ const { data } = await apiClient.post>(
+ `/orders/${id}/checkout`,
+ toCheckoutRequest(payload)
+ )
+ return data.data
+}
+
+export function createCheckout(id: number, payload: SubmitCheckoutPayload) {
+ return submitCheckout(id, payload)
+}
+
+export async function confirmCheckout(id: number) {
+ const { data } = await apiClient.post>(
+ `/orders/${id}/checkout/confirm`
+ )
+ return data.data
+}
+
+export async function acceptCheckout(id: number) {
+ const { data } = await apiClient.post>(`/orders/${id}/checkout/accept`)
+ return data.data
+}
+
+export async function rejectCheckout(id: number) {
+ const { data } = await apiClient.post>(`/orders/${id}/checkout/reject`)
+ return data.data
+}
+
+export async function counterCheckout(id: number, payload: SubmitCheckoutPayload) {
+ const { data } = await apiClient.post>(
+ `/orders/${id}/checkout/counter`,
+ toCheckoutRequest(payload)
+ )
+ return data.data
+}
+
+export async function fetchAdminOrders(page = 1, pageSize = 20) {
+ const { data } = await apiClient.get>>('/admin/orders', {
+ params: { page, page_size: pageSize },
+ })
+ return data.data
+}
+
+export async function fetchAdminOrder(id: string | number) {
+ const { data } = await apiClient.get>(`/admin/orders/${id}`)
+ return data.data
+}
+
+export async function fetchAdminHandoffRecords(id: string | number) {
+ const { data } = await apiClient.get>(`/admin/orders/${id}/handoffs`)
+ return data.data
+}
+
+export async function adminCloseOrder(id: number, reason: string) {
+ const { data } = await apiClient.post>(`/admin/orders/${id}/close`, { reason })
+ return data.data
+}
+
+export async function adminMarkOrderAbnormal(id: number, reason: string) {
+ const { data } = await apiClient.post>(`/admin/orders/${id}/abnormal`, { reason })
+ return data.data
+}
+
+export async function adminRefundStatus(id: number) {
+ const { data } = await apiClient.get>(`/admin/orders/${id}/refund-status`)
+ return data.data
+}
+
+export async function adminRefundOrder(id: number) {
+ const { data } = await apiClient.post>(`/admin/orders/${id}/refund`)
+ return data.data
+}
+
diff --git a/frontend/src/features/orders/views/MobileOrderDetailView.vue b/frontend/src/features/orders/views/MobileOrderDetailView.vue
index 3e297c9..b029ead 100644
--- a/frontend/src/features/orders/views/MobileOrderDetailView.vue
+++ b/frontend/src/features/orders/views/MobileOrderDetailView.vue
@@ -6,7 +6,7 @@ import { showToast, showDialog } from 'vant'
import { fetchOrderChat } from '@/features/chats/api/chats'
import { createDispute } from '@/features/disputes/api/disputes'
import { uploadFile } from '@/shared/api/files'
-import { formatMoney } from '@/shared/utils/money'
+import { centToYuan, formatMoney } from '@/shared/utils/money'
import {
acceptCheckout,
cancelOrder,
@@ -506,7 +506,9 @@ function checkoutContentWithSummary() {
}
if (Number(checkoutForm.value.coin_consumed_m || 0) > 0) {
lines.push(
- `哈夫币消耗:${quantity(Number(checkoutForm.value.coin_consumed_m))}M,预计剩余${quantity(remainingHafCoinM.value)}M`
+ `哈夫币消耗:${quantity(Number(checkoutForm.value.coin_consumed_m))}M,预计剩余${quantity(
+ remainingHafCoinM.value
+ )}M`
)
}
if (lines.length === 0) {
@@ -553,17 +555,26 @@ function formatHandoffRecordType(type: string) {
return typeMap[type] || type
}
+function amountYuan(cent: unknown, legacyYuan?: unknown) {
+ if (cent !== undefined && cent !== null) return centToYuan(readNumber(cent))
+ return readNumber(legacyYuan)
+}
+
function orderRentAmount(item: Order) {
if (item.owner_id === session.userId)
- return Number(item.owner_rent_amount ?? item.display_amount ?? 0)
- if (item.renter_id === session.userId) return Number(item.rent_amount ?? item.display_amount ?? 0)
- return Number(item.display_amount ?? 0)
+ return amountYuan(item.owner_rent_amount_cent, item.owner_rent_amount ?? item.display_amount)
+ 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)
}
function ownerActualIncome(item: Order) {
if (item.owner_id !== session.userId) return null
- const value = item.checkout?.owner_income_amount
- return typeof value === 'number' ? value : 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
}
function quantity(value: unknown) {
@@ -583,10 +594,16 @@ function isRecord(value: unknown): value is Record {
function hydrateCounterForm() {
if (!order.value?.checkout) return
const checkout = order.value.checkout
- counterForm.value.consumable_amount = checkout.consumable_amount
+ counterForm.value.consumable_amount = amountYuan(
+ checkout.consumable_amount_cent,
+ checkout.consumable_amount
+ )
counterForm.value.coin_consumed_m = checkout.coin_consumed_m
- counterForm.value.other_amount = checkout.other_amount
- counterForm.value.deposit_deduct_amount = checkout.deposit_deduct_amount
+ 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
+ )
}
function linesToList(value: string) {
@@ -676,9 +693,15 @@ async function copyListingCode() {
押金
- ¥{{ money(order.deposit_amount) }}
- 已免押 ¥{{ money(order.deposit_waived_amount) }}¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}
+ 已免押 ¥{{
+ money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount))
+ }}
@@ -929,30 +952,58 @@ async function copyListingCode() {
>
结账结算账单
-
+
+
-
押金金额
- ¥{{ money(order.deposit_amount) }}
- 免 ¥{{ money(order.deposit_waived_amount) }} 0"
+ >免 ¥{{ money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount)) }}
diff --git a/frontend/src/features/orders/views/OrderDetailView.vue b/frontend/src/features/orders/views/OrderDetailView.vue
index 0aa6bdb..babd286 100644
--- a/frontend/src/features/orders/views/OrderDetailView.vue
+++ b/frontend/src/features/orders/views/OrderDetailView.vue
@@ -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 { formatMoney } from '@/shared/utils/money'
+import { centToYuan, formatMoney } from '@/shared/utils/money'
import {
acceptCheckout,
cancelOrder,
@@ -600,17 +600,24 @@ function money(value: unknown) {
return formatMoney(readNumber(value))
}
+function amountYuan(cent: unknown, legacyYuan?: unknown) {
+ if (cent !== undefined && cent !== null) return centToYuan(readNumber(cent))
+ return readNumber(legacyYuan)
+}
+
function orderRentAmount(item: Order) {
if (item.owner_id === session.userId)
- return Number(item.owner_rent_amount ?? item.display_amount ?? 0)
- if (item.renter_id === session.userId) return Number(item.rent_amount ?? item.display_amount ?? 0)
- return Number(item.display_amount ?? 0)
+ return amountYuan(item.owner_rent_amount_cent, item.owner_rent_amount ?? item.display_amount)
+ 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)
}
function ownerActualIncome(item: Order) {
if (item.owner_id !== session.userId) return null
- const value = item.checkout?.owner_income_amount
- return typeof value === 'number' ? value : 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
}
function quantity(value: unknown) {
@@ -630,10 +637,10 @@ function isRecord(value: unknown): value is Record {
function hydrateCounterForm() {
if (!order.value?.checkout) return
const checkout = order.value.checkout
- counterForm.value.consumable_amount = checkout.consumable_amount
+ counterForm.value.consumable_amount = amountYuan(checkout.consumable_amount_cent, checkout.consumable_amount)
counterForm.value.coin_consumed_m = checkout.coin_consumed_m
- counterForm.value.other_amount = checkout.other_amount
- counterForm.value.deposit_deduct_amount = checkout.deposit_deduct_amount
+ 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)
}
function linesToList(value: string) {
@@ -767,9 +774,9 @@ async function copyListingCode() {
押金
- ¥{{ money(order.deposit_amount) }}
- 已免押 ¥{{ money(order.deposit_waived_amount) }}¥{{ money(amountYuan(order.deposit_amount_cent, order.deposit_amount)) }}
+ 已免押 ¥{{ money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount)) }}
@@ -951,32 +958,32 @@ async function copyListingCode() {
实际结算租金
- ¥{{ money(order.checkout.display_amount) }}
+ ¥{{ money(amountYuan(order.checkout.display_amount_cent, order.checkout.display_amount)) }}
预收押金
- ¥{{ money(order.checkout.deposit_amount) }}
- 已免押 ¥{{ money(order.deposit_waived_amount) }} 0"
+ >已免押 ¥{{ money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount)) }}
额外消耗品已用
- ¥{{ money(order.checkout.consumable_amount) }}
+ ¥{{ money(amountYuan(order.checkout.consumable_amount_cent, order.checkout.consumable_amount)) }}
押金赔付扣除
- ¥{{ money(order.checkout.deposit_deduct_amount) }}
+ ¥{{ money(amountYuan(order.checkout.deposit_deduct_amount_cent, order.checkout.deposit_deduct_amount)) }}
退还租客(未使用租金 + 剩余押金)
- ¥{{ money(order.checkout.renter_refund_amount) }}
+ ¥{{ money(amountYuan(order.checkout.renter_refund_amount_cent, order.checkout.renter_refund_amount)) }}
号主最终收入(租金 + 押金赔付)
- ¥{{ money(order.checkout.owner_income_amount) }}
+ ¥{{ money(amountYuan(order.checkout.owner_income_amount_cent, order.checkout.owner_income_amount)) }}
@@ -1031,7 +1038,7 @@ async function copyListingCode() {
v-model="counterForm.deposit_deduct_amount"
class="full-control"
:min="0"
- :max="order.deposit_amount"
+ :max="amountYuan(order.deposit_amount_cent, order.deposit_amount)"
:precision="0"
controls-position="right"
/>
diff --git a/frontend/src/features/orders/views/OrdersView.vue b/frontend/src/features/orders/views/OrdersView.vue
index 640a802..20a7ce8 100644
--- a/frontend/src/features/orders/views/OrdersView.vue
+++ b/frontend/src/features/orders/views/OrdersView.vue
@@ -5,7 +5,7 @@ import { useRoute, useRouter } from 'vue-router'
import { CopyDocument, Search } from '@element-plus/icons-vue'
import { fetchOrders, type Order } from '@/features/orders'
-import { formatMoney } from '@/shared/utils/money'
+import { centToYuan, formatMoney } from '@/shared/utils/money'
import { useSessionStore } from '@/stores/session'
import { orderStatusLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
@@ -127,16 +127,22 @@ function amountLabel(order: Order) {
return isRenter(order) ? '支付租金' : '预计租金'
}
+function amountYuan(cent: unknown, legacyYuan?: unknown) {
+ if (cent !== undefined && cent !== null) return centToYuan(Number(cent || 0))
+ return Number(legacyYuan || 0)
+}
+
function orderRentAmount(order: Order) {
- if (isOwner(order)) return Number(order.owner_rent_amount ?? order.display_amount ?? 0)
- if (isRenter(order)) return Number(order.rent_amount ?? order.display_amount ?? 0)
- return Number(order.display_amount ?? 0)
+ 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)
}
function ownerActualIncome(order: Order) {
if (!isOwner(order)) return null
- const value = order.checkout?.owner_income_amount
- return typeof value === 'number' ? value : 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
}
function money(value: unknown) {
@@ -351,9 +357,9 @@ function getCountdownMinutes(order: Order) {
押金
- ¥{{ money(order.deposit_amount) }}
- 免 ¥{{ money(order.deposit_waived_amount) }} 0"
+ >免 ¥{{ money(amountYuan(order.deposit_waived_amount_cent, order.deposit_waived_amount)) }}
diff --git a/frontend/src/features/wallet/composables/useWallet.ts b/frontend/src/features/wallet/composables/useWallet.ts
index d45637a..feea445 100644
--- a/frontend/src/features/wallet/composables/useWallet.ts
+++ b/frontend/src/features/wallet/composables/useWallet.ts
@@ -8,8 +8,8 @@ export function useWallet() {
const loading = ref(false)
const error = ref
(null)
- const availableBalance = computed(() => balance.value?.available_balance ?? 0)
- const frozenBalance = computed(() => balance.value?.frozen_balance ?? 0)
+ const availableBalance = computed(() => balance.value?.available_balance_cent ?? 0)
+ const frozenBalance = computed(() => balance.value?.frozen_balance_cent ?? 0)
const totalBalance = computed(() => availableBalance.value + frozenBalance.value)
async function loadBalance() {
diff --git a/frontend/src/features/wallet/views/WalletView.vue b/frontend/src/features/wallet/views/WalletView.vue
index 5fb3bda..249b1b9 100644
--- a/frontend/src/features/wallet/views/WalletView.vue
+++ b/frontend/src/features/wallet/views/WalletView.vue
@@ -25,7 +25,7 @@ import {
import type { PaymentOrder } from '@/features/orders'
import { balanceTypeLabel, ledgerDirectionLabel, walletStatusLabel } from '@/utils/statusLabels'
import { formatDateTime } from '@/utils/time'
-import { formatCent, formatCentWithSymbol } from '@/shared/utils/money'
+import { formatCentWithSymbol, formatMoney } from '@/shared/utils/money'
const router = useRouter()
const loading = ref(false)
@@ -276,7 +276,7 @@ function amountPrefix(direction: string) {
当前可用
- {{ account ? formatMoney(account.available_balance) : '¥0.00' }}
+ {{ account ? formatCentWithSymbol(account.available_balance_cent) : '¥0.0' }}
申请提现
@@ -374,10 +374,10 @@ function amountPrefix(direction: string) {
- {{ amountPrefix(row.direction) }}{{ formatMoney(row.amount) }}
+ {{ amountPrefix(row.direction) }}{{ formatCentWithSymbol(row.amount_cent) }}
{{ balanceTypeLabel(row.balance_type) }}
- {{ formatMoney(row.balance_after) }}
+ {{ formatCentWithSymbol(row.balance_after_cent) }}
{{ row.remark || '-' }}
{{ formatDateTime(row.created_at) }}
diff --git a/frontend/src/features/wallet/views/WithdrawalView.vue b/frontend/src/features/wallet/views/WithdrawalView.vue
index bb12621..8c111e9 100644
--- a/frontend/src/features/wallet/views/WithdrawalView.vue
+++ b/frontend/src/features/wallet/views/WithdrawalView.vue
@@ -13,7 +13,7 @@ import {
type WithdrawalRequest,
} from '../api/withdrawal'
import { fetchWalletBalance, type WalletAccount } from '../api/wallet'
-import { formatMoney, formatMoneyWithSymbol } from '@/shared/utils/money'
+import { formatMoney, formatMoneyWithSymbol, formatCent, yuanToCent } from '@/shared/utils/money'
const router = useRouter()
@@ -74,7 +74,7 @@ const canWithdraw = computed(() => {
withdrawForm.value.amount >= MIN_AMOUNT &&
withdrawForm.value.amount <= MAX_AMOUNT &&
account.value &&
- withdrawForm.value.amount <= account.value.available_balance
+ yuanToCent(withdrawForm.value.amount) <= account.value.available_balance_cent
)
})
@@ -95,7 +95,10 @@ async function handleSubmit() {
)
submitting.value = true
- await createWithdrawal(withdrawForm.value)
+ await createWithdrawal({
+ payment_account_id: withdrawForm.value.payment_account_id,
+ amount_cent: yuanToCent(withdrawForm.value.amount),
+ })
ElMessage.success('提现申请已提交')
withdrawForm.value.amount = 0
await loadData()
@@ -176,7 +179,7 @@ function accountTypeLabel(type: string) {
可用余额
- ¥{{ formatMoney(account?.available_balance) }}
+ ¥{{ formatCent(account?.available_balance_cent) }}
@@ -184,7 +187,7 @@ function accountTypeLabel(type: string) {
冻结余额
- ¥{{ formatMoney(account?.frozen_balance) }}
+ ¥{{ formatCent(account?.frozen_balance_cent) }}
@@ -258,14 +261,14 @@ function accountTypeLabel(type: string) {
- 余额不足,可用余额:¥{{ formatMoney(account.available_balance) }}
+ 余额不足,可用余额:¥{{ formatCent(account.available_balance_cent) }}
@@ -309,7 +312,7 @@ function accountTypeLabel(type: string) {
- ¥{{ formatMoney(row.amount) }}
+ ¥{{ formatCent(row.amount_cent) }}