feat(admin): 统一订单与支付枚举中文映射
This commit is contained in:
@@ -48,6 +48,16 @@ import {
|
||||
} from '@/features/admin/api'
|
||||
import { AdminPageHeader } from '@/features/admin/components/AdminPageHeader'
|
||||
import { StatusTag } from '@/features/admin/components/StatusTag'
|
||||
import {
|
||||
disputeStatusLabel,
|
||||
disputeTypeLabel,
|
||||
handoffRecordTypeLabel,
|
||||
participantTypeLabel,
|
||||
paymentBizTypeLabel,
|
||||
paymentProviderLabel,
|
||||
processActionLabel,
|
||||
processStageLabel,
|
||||
} from '@/features/admin/enumLabels'
|
||||
import {
|
||||
accountSourceLabel,
|
||||
checkoutStatusMap,
|
||||
@@ -148,14 +158,6 @@ const disputeTypeOptions = [
|
||||
{ label: '结账金额争议', value: 'checkout_amount' },
|
||||
]
|
||||
|
||||
const handoffTypeText: Record<string, string> = {
|
||||
handoff: '交接',
|
||||
return: '归还',
|
||||
checkout: '结账',
|
||||
submit: '提交',
|
||||
confirm: '确认',
|
||||
}
|
||||
|
||||
function errorText(error: unknown) {
|
||||
const response = (error as { response?: { data?: { message?: string } } })?.response
|
||||
if (response?.data?.message) return response.data.message
|
||||
@@ -181,7 +183,7 @@ const paymentColumns: TableColumnsType<AdminPaymentRow> = [
|
||||
title: '类型',
|
||||
dataIndex: 'biz_type',
|
||||
width: 120,
|
||||
render: value => <Tag bordered={false}>{formatText(value)}</Tag>,
|
||||
render: value => <Tag bordered={false}>{paymentBizTypeLabel(value)}</Tag>,
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
@@ -196,7 +198,12 @@ const paymentColumns: TableColumnsType<AdminPaymentRow> = [
|
||||
width: 110,
|
||||
render: value => <StatusTag meta={readStatusMeta(paymentStatusMap, value)} />,
|
||||
},
|
||||
{ title: '渠道', dataIndex: 'provider', width: 100, render: value => formatText(value) },
|
||||
{
|
||||
title: '渠道',
|
||||
dataIndex: 'provider',
|
||||
width: 100,
|
||||
render: value => paymentProviderLabel(value),
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'created_at',
|
||||
@@ -216,15 +223,17 @@ function ProcessTimeline({ events }: { events: AdminOrderProcessEvent[] }) {
|
||||
children: (
|
||||
<div className="admin-timeline-item">
|
||||
<div className="admin-timeline-item__head">
|
||||
<strong>{formatText(event.action || event.stage)}</strong>
|
||||
<strong>{processActionLabel(event.action || event.stage)}</strong>
|
||||
<span>{formatDateTime(event.created_at)}</span>
|
||||
</div>
|
||||
{event.content ? <p>{event.content}</p> : null}
|
||||
{event.reason ? <p>原因:{event.reason}</p> : null}
|
||||
<div className="admin-timeline-item__meta">
|
||||
<span>操作方:{formatText(event.actor_name || event.actor_type)}</span>
|
||||
<span>
|
||||
操作方:{formatText(event.actor_name || participantTypeLabel(event.actor_type))}
|
||||
</span>
|
||||
{event.target_name ? <span>对象:{event.target_name}</span> : null}
|
||||
{event.stage ? <span>阶段:{event.stage}</span> : null}
|
||||
{event.stage ? <span>阶段:{processStageLabel(event.stage)}</span> : null}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
@@ -242,7 +251,7 @@ function HandoffRecords({ records }: { records: AdminOrderHandoffRecord[] }) {
|
||||
{records.map(record => (
|
||||
<article key={record.id} className="admin-record-item">
|
||||
<div className="admin-record-item__head">
|
||||
<strong>{handoffTypeText[record.type] ?? formatText(record.type)}</strong>
|
||||
<strong>{handoffRecordTypeLabel(record.type)}</strong>
|
||||
<span>{formatDateTime(record.created_at)}</span>
|
||||
</div>
|
||||
<p className="admin-record-item__content">{record.content || emptyText}</p>
|
||||
@@ -953,13 +962,14 @@ export function AdminOrderDetailPage() {
|
||||
<Descriptions column={{ xs: 1, sm: 2 }} size="small">
|
||||
<Descriptions.Item label="申诉单号">#{order.active_dispute.id}</Descriptions.Item>
|
||||
<Descriptions.Item label="类型">
|
||||
{formatText(order.active_dispute.type)}
|
||||
{disputeTypeLabel(order.active_dispute.type)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="发起方">
|
||||
{order.active_dispute.initiator_type} · {order.active_dispute.initiator_id}
|
||||
{participantTypeLabel(order.active_dispute.initiator_type)} ·{' '}
|
||||
{order.active_dispute.initiator_id}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="状态">
|
||||
{formatText(order.active_dispute.status)}
|
||||
{disputeStatusLabel(order.active_dispute.status)}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
@@ -7,6 +7,12 @@ import { fetchAdminPayments } from '@/features/admin/api'
|
||||
import { AdminPageHeader } from '@/features/admin/components/AdminPageHeader'
|
||||
import { DataTable } from '@/features/admin/components/DataTable'
|
||||
import { FilterBar, FilterField } from '@/features/admin/components/FilterBar'
|
||||
import {
|
||||
paymentBizTypeMap,
|
||||
paymentMethodLabel,
|
||||
paymentProviderLabel,
|
||||
paymentProviderMap,
|
||||
} from '@/features/admin/enumLabels'
|
||||
import type { AdminPaymentQuery, AdminPaymentRow } from '@/features/admin/types'
|
||||
import { useAdminSessionStore } from '@/stores/adminSession'
|
||||
import { formatDateTime, formatMoney, formatText } from '@/shared/utils/format'
|
||||
@@ -27,16 +33,12 @@ const statusOptions = [
|
||||
{ value: 'closed', label: '已关闭' },
|
||||
]
|
||||
|
||||
const bizTypeOptions = [
|
||||
{ value: 'order_pay', label: '订单支付' },
|
||||
{ value: 'main_recharge', label: '充值' },
|
||||
]
|
||||
const bizTypeOptions = Object.entries(paymentBizTypeMap).map(([value, label]) => ({ value, label }))
|
||||
|
||||
const providerOptions = [
|
||||
{ value: 'leshua', label: '拉卡拉' },
|
||||
{ value: 'shuncheng', label: '顺诚' },
|
||||
{ value: 'mock', label: '模拟支付' },
|
||||
]
|
||||
const providerOptions = Object.entries(paymentProviderMap).map(([value, label]) => ({
|
||||
value,
|
||||
label,
|
||||
}))
|
||||
|
||||
const statusMeta: Record<string, { label: string; color: string }> = {
|
||||
pending: { label: '待支付', color: 'gold' },
|
||||
@@ -91,8 +93,8 @@ const columns: TableColumnsType<AdminPaymentRow> = [
|
||||
width: 170,
|
||||
render: (_, row) => (
|
||||
<div className="admin-stack">
|
||||
<span>{formatText(row.provider)}</span>
|
||||
<span className="admin-mono">{formatText(row.pay_way)}</span>
|
||||
<span>{paymentProviderLabel(row.provider)}</span>
|
||||
<span className="admin-mono">{paymentMethodLabel(row.pay_way)}</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
disputeStatusLabel,
|
||||
disputeTypeLabel,
|
||||
handoffRecordTypeLabel,
|
||||
participantTypeLabel,
|
||||
paymentBizTypeLabel,
|
||||
paymentMethodLabel,
|
||||
paymentProviderLabel,
|
||||
processActionLabel,
|
||||
processStageLabel,
|
||||
} from '@/features/admin/enumLabels'
|
||||
|
||||
describe('paymentBizTypeLabel', () => {
|
||||
it('映射订单与退款业务类型', () => {
|
||||
expect(paymentBizTypeLabel('order_pay')).toBe('订单支付')
|
||||
expect(paymentBizTypeLabel('deposit')).toBe('押金支付')
|
||||
expect(paymentBizTypeLabel('admin_refund')).toBe('人工退款')
|
||||
})
|
||||
|
||||
it('未知值保留原值,空值显示占位符', () => {
|
||||
expect(paymentBizTypeLabel('new_biz_type')).toBe('new_biz_type')
|
||||
expect(paymentBizTypeLabel('')).toBe('—')
|
||||
expect(paymentBizTypeLabel(null)).toBe('—')
|
||||
})
|
||||
})
|
||||
|
||||
describe('paymentProviderLabel / paymentMethodLabel', () => {
|
||||
it('映射渠道与支付方式', () => {
|
||||
expect(paymentProviderLabel('leshua')).toBe('拉卡拉')
|
||||
expect(paymentProviderLabel('demo')).toBe('演示渠道')
|
||||
expect(paymentMethodLabel('wechat')).toBe('微信支付')
|
||||
expect(paymentMethodLabel('alipay')).toBe('支付宝')
|
||||
})
|
||||
|
||||
it('未知值保留原值', () => {
|
||||
expect(paymentProviderLabel('new_provider')).toBe('new_provider')
|
||||
expect(paymentMethodLabel('new_method')).toBe('new_method')
|
||||
})
|
||||
})
|
||||
|
||||
describe('processActionLabel / processStageLabel', () => {
|
||||
it('映射真实流程动作与阶段', () => {
|
||||
expect(processActionLabel('owner_handoff_submitted')).toBe('号主提交交接')
|
||||
expect(processActionLabel('platform_checkout_confirmed')).toBe('客服确认结账')
|
||||
expect(processStageLabel('handoff')).toBe('交接')
|
||||
})
|
||||
|
||||
it('兼容 order.xxx 旧动作格式', () => {
|
||||
expect(processActionLabel('order.created')).toBe('创建订单')
|
||||
expect(processActionLabel('order.paid')).toBe('支付完成')
|
||||
expect(processActionLabel('order.handoff_received')).toBe('租客确认收号')
|
||||
})
|
||||
|
||||
it('未知动作保留原值', () => {
|
||||
expect(processActionLabel('order.unknown_action')).toBe('order.unknown_action')
|
||||
expect(processStageLabel('unknown_stage')).toBe('unknown_stage')
|
||||
})
|
||||
})
|
||||
|
||||
describe('交接与申诉映射', () => {
|
||||
it('映射交接记录类型', () => {
|
||||
expect(handoffRecordTypeLabel('owner_handoff')).toBe('号主交接')
|
||||
expect(handoffRecordTypeLabel('platform_checkout_dispute_opened')).toBe('客服发起结账争议')
|
||||
})
|
||||
|
||||
it('映射申诉类型、状态与发起方', () => {
|
||||
expect(disputeTypeLabel('checkout')).toBe('结账争议')
|
||||
expect(disputeStatusLabel('open')).toBe('处理中')
|
||||
expect(participantTypeLabel('user')).toBe('用户')
|
||||
expect(participantTypeLabel('admin')).toBe('客服')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,154 @@
|
||||
/** 后台订单/支付相关枚举的中文展示。未知值保留原始 code,方便排查新枚举。 */
|
||||
|
||||
function labelOf(map: Record<string, string>, value?: string | null) {
|
||||
const code = (value ?? '').trim()
|
||||
if (!code) return '—'
|
||||
return map[code] ?? code
|
||||
}
|
||||
|
||||
export const paymentBizTypeMap: Record<string, string> = {
|
||||
order_pay: '订单支付',
|
||||
deposit: '押金支付',
|
||||
wallet_recharge: '钱包充值',
|
||||
main_recharge: '充值',
|
||||
cancel_refund: '取消退款',
|
||||
admin_close_refund: '客服关闭退款',
|
||||
admin_refund: '人工退款',
|
||||
checkout_refund: '结账退款',
|
||||
deposit_refund: '押金退款',
|
||||
rent_refund: '租金退款',
|
||||
arbitration_refund: '仲裁退款',
|
||||
admin_seal_refund: '封存退款',
|
||||
mohong_pay: '撞车支付',
|
||||
mohong_refund: '撞车退款',
|
||||
quality_owner_pay: '优质号主保证金',
|
||||
}
|
||||
|
||||
export function paymentBizTypeLabel(value?: string | null) {
|
||||
return labelOf(paymentBizTypeMap, value)
|
||||
}
|
||||
|
||||
export const paymentProviderMap: Record<string, string> = {
|
||||
leshua: '拉卡拉',
|
||||
shuncheng: '顺诚',
|
||||
mock: '模拟支付',
|
||||
demo: '演示渠道',
|
||||
}
|
||||
|
||||
export function paymentProviderLabel(value?: string | null) {
|
||||
return labelOf(paymentProviderMap, value)
|
||||
}
|
||||
|
||||
export const paymentMethodMap: Record<string, string> = {
|
||||
wechat: '微信支付',
|
||||
alipay: '支付宝',
|
||||
unionpay: '银联',
|
||||
qq: 'QQ 钱包',
|
||||
mock: '模拟支付',
|
||||
}
|
||||
|
||||
export function paymentMethodLabel(value?: string | null) {
|
||||
return labelOf(paymentMethodMap, value)
|
||||
}
|
||||
|
||||
export const processStageMap: Record<string, string> = {
|
||||
create: '创建',
|
||||
payment: '支付',
|
||||
handoff: '交接',
|
||||
checkout: '结账',
|
||||
settlement: '结算',
|
||||
dispute: '争议',
|
||||
}
|
||||
|
||||
export function processStageLabel(value?: string | null) {
|
||||
return labelOf(processStageMap, value)
|
||||
}
|
||||
|
||||
export const processActionMap: Record<string, string> = {
|
||||
created: '创建订单',
|
||||
paid: '支付完成',
|
||||
owner_handoff_submitted: '号主提交交接',
|
||||
handoff_submitted: '号主提交交接',
|
||||
platform_handoff_submitted: '客服代交接',
|
||||
admin_force_handoff: '客服确认交接',
|
||||
renter_received_confirmed: '租客确认收号',
|
||||
handoff_received: '租客确认收号',
|
||||
checkout_submitted: '租客发起结账',
|
||||
checkout_countered: '修改结账方案',
|
||||
checkout_confirmed: '号主确认结账',
|
||||
checkout_accepted: '租客接受结账方案',
|
||||
checkout_disputed: '发起结账争议',
|
||||
platform_checkout_countered: '客服修改结账方案',
|
||||
platform_checkout_confirmed: '客服确认结账',
|
||||
platform_checkout_dispute_opened: '客服发起结账争议',
|
||||
offline_settlement_confirmed: '确认线下结算',
|
||||
deposit_held: '暂扣押金',
|
||||
deposit_released: '归还暂扣押金',
|
||||
}
|
||||
|
||||
export function processActionLabel(value?: string | null) {
|
||||
const code = (value ?? '').trim()
|
||||
if (!code) return '—'
|
||||
const direct = processActionMap[code]
|
||||
if (direct) return direct
|
||||
// 兼容手工数据/旧数据里的 order.xxx 形式。
|
||||
if (code.startsWith('order.')) {
|
||||
const suffix = code.slice('order.'.length)
|
||||
const mapped = processActionMap[suffix]
|
||||
if (mapped) return mapped
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
export const handoffRecordTypeMap: Record<string, string> = {
|
||||
owner_handoff: '号主交接',
|
||||
owner_return: '号主归还',
|
||||
renter_return: '租客归还',
|
||||
platform_handoff: '客服代交接',
|
||||
admin_force_handoff: '客服确认交接',
|
||||
renter_checkout: '租客发起结账',
|
||||
platform_checkout_counter: '客服修改结账方案',
|
||||
platform_checkout_dispute_opened: '客服发起结账争议',
|
||||
}
|
||||
|
||||
export function handoffRecordTypeLabel(value?: string | null) {
|
||||
return labelOf(handoffRecordTypeMap, value)
|
||||
}
|
||||
|
||||
export const disputeTypeMap: Record<string, string> = {
|
||||
cannot_login: '无法登录',
|
||||
false_description: '描述不符',
|
||||
account_banned: '账号封禁',
|
||||
asset_loss: '资产损失',
|
||||
haf_coin_dispute: '哈夫币争议',
|
||||
handoff_timeout: '交接超时',
|
||||
return_timeout: '归还超时',
|
||||
checkout_amount: '结账金额争议',
|
||||
checkout: '结账争议',
|
||||
checkout_dispute: '结账争议',
|
||||
}
|
||||
|
||||
export function disputeTypeLabel(value?: string | null) {
|
||||
return labelOf(disputeTypeMap, value)
|
||||
}
|
||||
|
||||
export const disputeStatusMap: Record<string, string> = {
|
||||
open: '处理中',
|
||||
processing: '处理中',
|
||||
resolved: '已解决',
|
||||
cancelled: '已取消',
|
||||
}
|
||||
|
||||
export function disputeStatusLabel(value?: string | null) {
|
||||
return labelOf(disputeStatusMap, value)
|
||||
}
|
||||
|
||||
export const participantTypeMap: Record<string, string> = {
|
||||
user: '用户',
|
||||
admin: '客服',
|
||||
system: '系统',
|
||||
}
|
||||
|
||||
export function participantTypeLabel(value?: string | null) {
|
||||
return labelOf(participantTypeMap, value)
|
||||
}
|
||||
Reference in New Issue
Block a user