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) { > 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)) +} - + - + 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() { 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) }}免 ¥{{ 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) }}已免押 ¥{{ 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) }}免 ¥{{ 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) {