From cc88f46960d40f4e2b39f46a04d818fe35c77d1c Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sun, 21 Jun 2026 12:26:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=A2=E5=8D=95=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/views/AdminOrderDetailView.vue | 745 ++++++++++++++++-- 1 file changed, 679 insertions(+), 66 deletions(-) diff --git a/frontend/src/features/admin/views/AdminOrderDetailView.vue b/frontend/src/features/admin/views/AdminOrderDetailView.vue index 24dfa90..69538c4 100644 --- a/frontend/src/features/admin/views/AdminOrderDetailView.vue +++ b/frontend/src/features/admin/views/AdminOrderDetailView.vue @@ -17,9 +17,19 @@ import { type RefundStatus, } from '@/features/orders' import { fetchAdminPayments, type AdminPayment } from '@/features/admin/api/adminPayments' +import { + getSnapshotHafCoinM, + readSnapshot, + readSnapshotResources, +} from '@/features/orders/composables/useOrderSnapshot' import { adminPath } from '@/shared/utils/adminPath' -import { centToYuan, formatCentWithSymbol, formatMoney } from '@/shared/utils/money' -import { handoffStatusLabel, orderStatusLabel } from '@/shared/utils/statusLabels' +import { formatCentWithSymbol } from '@/shared/utils/money' +import { + disputeStatusLabel, + handoffStatusLabel, + orderStatusLabel, + settlementStatusLabel, +} from '@/shared/utils/statusLabels' import { formatDateTime } from '@/shared/utils/time' import { formatListingNo } from '@/shared/utils/listingDisplay' @@ -78,6 +88,36 @@ const actionTitle = computed(() => { const closeActionTip = '关闭订单并归档商品/账号;已支付订单会按租金+实付押金全量原路退款。' const refundActionTip = '仅发起后台人工全量原路退款,不关闭订单或调整商品/账号状态。' const refundButtonDisabled = computed(() => refundStatus.value?.refund_status === 'refunded') +const orderTotalCent = computed( + () => Number(order.value?.rent_amount_cent || 0) + Number(order.value?.deposit_amount_cent || 0) +) +const latestPayment = computed(() => { + return [...paymentRecords.value].sort( + (a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime() + )[0] +}) +const paidOrderPayment = computed(() => + paymentRecords.value.find(item => item.biz_type === 'order_pay' && item.status === 'paid') +) +const currentSnapshot = computed(() => readSnapshot(order.value)) +const snapshotHafCoinM = computed(() => getSnapshotHafCoinM(order.value)) +const snapshotResources = computed(() => readSnapshotResources(order.value).slice(0, 6)) +const snapshotSeasonTags = computed(() => { + const tags = currentSnapshot.value?.season_tags + return Array.isArray(tags) ? tags.map(item => String(item)).filter(Boolean) : [] +}) +const accountSnapshotItems = computed(() => { + const snapshot = currentSnapshot.value + if (!snapshot) return [] + return [ + { label: '账号ID', value: displayValue(snapshot.account_id) }, + { label: '账号标题', value: displayValue(snapshot.title) }, + { label: '游戏名称', value: displayValue(snapshot.game_name) }, + { label: '所在区服', value: displayValue(snapshot.server_region) }, + { label: '登录平台', value: displayValue(snapshot.login_platform) }, + { label: '段位等级', value: displayValue(snapshot.rank_level) }, + ].filter(item => item.value !== '-') +}) onMounted(loadOrder) @@ -160,15 +200,6 @@ function orderEstimatedEndAt() { return new Date(new Date(rentedAt).getTime() + durationHours * 60 * 60 * 1000).toISOString() } -function money(value: unknown) { - return formatMoney(Number(value || 0)) -} - -function amountYuan(cent: unknown) { - if (cent !== undefined && cent !== null) return centToYuan(Number(cent || 0)) - return 0 -} - async function handleRefund() { if (!order.value) return refunding.value = true @@ -244,8 +275,8 @@ function paymentBizTypeLabel(type: string) { return map[type] || type } -function moneyCent(value: number) { - return formatCentWithSymbol(value) +function moneyCent(value: number | undefined | null) { + return formatCentWithSymbol(Number(value || 0)) } function firstQueryValue(value: unknown) { @@ -264,6 +295,85 @@ function formatHandoffRecordType(type: string) { } return typeMap[type] || type } + +function orderStatusType(status: string) { + if (['completed', 'renting'].includes(status)) return 'success' + if (['overdue', 'abnormal', 'checkout_disputing'].includes(status)) return 'danger' + if (['pending_payment', 'pending_handoff', 'pending_checkout_confirm'].includes(status)) { + return 'warning' + } + if (['cancelled', 'closed'].includes(status)) return 'info' + return 'primary' +} + +function settlementStatusType(status: string) { + if (['settled', 'refunded', 'arbitrated'].includes(status)) return 'success' + if (['disputed', 'frozen'].includes(status)) return 'danger' + if (['pending', 'unsettled'].includes(status)) return 'warning' + return 'info' +} + +function refundStatusType(status: string) { + if (status === 'refunded') return 'success' + if (status === 'failed') return 'danger' + if (['pending', 'refunding'].includes(status)) return 'warning' + return 'info' +} + +function checkoutStatusLabel(status: string) { + const map: Record = { + submitted: '待确认', + countered: '号主已修正', + accepted: '已接受', + disputed: '争议中', + } + return map[status] || settlementStatusLabel(status) +} + +function priceRoleLabel(role?: string) { + const map: Record = { + renter: '租客视角', + owner: '号主视角', + admin: '客服处理', + } + return map[role || ''] || role || '-' +} + +function disputeTypeLabel(type: string) { + const map: Record = { + handoff: '交接申诉', + checkout: '结账争议', + order: '订单争议', + } + return map[type] || type || '-' +} + +function userDisplay(phone: string | undefined, id: number) { + return phone ? `${phone} / ID ${id}` : `ID ${id}` +} + +function displayValue(value: unknown) { + if (value === undefined || value === null || value === '') return '-' + if (Array.isArray(value)) + return ( + value + .map(item => String(item)) + .filter(Boolean) + .join('、') || '-' + ) + if (typeof value === 'object') return JSON.stringify(value) + return String(value) +} + +function quantity(value: unknown) { + return Number(value || 0).toLocaleString('zh-CN', { + maximumFractionDigits: 2, + }) +} + +function paymentPaidAt(record: AdminPayment) { + return record.paid_at || record.updated_at || record.created_at +} + +