feat(mobile): 接入移动端订单与消息中心

This commit is contained in:
yml2213
2026-10-30 12:46:01 +08:00
parent 17b985a4a4
commit e8a20ebea7
17 changed files with 2153 additions and 30 deletions
+47
View File
@@ -0,0 +1,47 @@
import { useInfiniteQuery, useQuery } from '@tanstack/react-query'
import { apiClient, unwrapData } from '@/shared/api/client'
import type { ApiResponse } from '@/shared/api/types'
import type { UserOrderDetail, UserOrderPage } from '@/features/orders/types'
export const MY_ORDER_PAGE_SIZE = 20
export function fetchMyOrders(page = 1, pageSize = MY_ORDER_PAGE_SIZE) {
return unwrapData<Partial<UserOrderPage>>(
apiClient.get<ApiResponse<Partial<UserOrderPage>>>('/orders', {
params: { page, page_size: pageSize },
})
).then(data => ({
items: data.items ?? [],
total: data.total ?? 0,
page: data.page ?? page,
page_size: data.page_size ?? pageSize,
}))
}
export function useMyOrders(enabled = true) {
return useInfiniteQuery({
queryKey: ['my-orders'],
queryFn: ({ pageParam }) => fetchMyOrders(pageParam, MY_ORDER_PAGE_SIZE),
initialPageParam: 1,
getNextPageParam: last =>
last.page * last.page_size < last.total ? last.page + 1 : undefined,
enabled,
})
}
export function fetchMyOrder(id: number | string) {
return unwrapData<UserOrderDetail>(apiClient.get<ApiResponse<UserOrderDetail>>(`/orders/${id}`))
}
export function useMyOrder(id?: string, enabled = true) {
return useQuery({
queryKey: ['my-order', id],
queryFn: () => fetchMyOrder(id as string),
enabled: Boolean(id) && enabled,
})
}
export async function cancelMyOrder(id: number | string) {
await apiClient.post(`/orders/${id}/cancel`)
}
+88
View File
@@ -0,0 +1,88 @@
export type MobileTone = 'default' | 'primary' | 'success' | 'warning' | 'danger'
export interface MobileStatus {
label: string
tone: MobileTone
}
const orderStatus: Record<string, MobileStatus> = {
pending_payment: { label: '待支付', tone: 'warning' },
pending_handoff: { label: '待交接', tone: 'primary' },
renting: { label: '使用中', tone: 'primary' },
overdue: { label: '已逾期', tone: 'danger' },
pending_checkout_confirm: { label: '待确认结账', tone: 'warning' },
pending_checkout_accept: { label: '待确认修正', tone: 'warning' },
checkout_disputing: { label: '结账争议', tone: 'danger' },
disputing: { label: '申诉中', tone: 'danger' },
completed: { label: '已完成', tone: 'success' },
cancelled: { label: '已取消', tone: 'default' },
closed: { label: '已关闭', tone: 'default' },
abnormal: { label: '客服处理中', tone: 'danger' },
}
const handoffStatus: Record<string, MobileStatus> = {
none: { label: '未开始', tone: 'default' },
pending_owner: { label: '待号主交接', tone: 'primary' },
owner_timeout: { label: '交接超时', tone: 'danger' },
pending_renter_confirm: { label: '待确认收号', tone: 'primary' },
received: { label: '已收号', tone: 'success' },
return_overdue: { label: '归还逾期', tone: 'danger' },
pending_owner_checkout: { label: '待号主结账', tone: 'warning' },
pending_renter_checkout: { label: '待确认修正', tone: 'warning' },
checkout_disputed: { label: '结账争议', tone: 'danger' },
returned: { label: '已归还', tone: 'success' },
renter_confirm_timeout: { label: '确认超时', tone: 'danger' },
owner_return_confirm_timeout: { label: '结账超时', tone: 'danger' },
owner_checkout_confirm_timeout: { label: '结账超时', tone: 'danger' },
cancelled: { label: '已取消', tone: 'default' },
admin_closed: { label: '已关闭', tone: 'default' },
admin_abnormal: { label: '客服处理中', tone: 'danger' },
arbitrated: { label: '已仲裁', tone: 'success' },
}
const settlementStatus: Record<string, MobileStatus> = {
unsettled: { label: '未结算', tone: 'default' },
pending: { label: '待结算', tone: 'warning' },
frozen: { label: '冻结中', tone: 'danger' },
settled: { label: '已结算', tone: 'success' },
refunded: { label: '已退款', tone: 'primary' },
cancelled: { label: '结算已取消', tone: 'default' },
closed: { label: '结算已关闭', tone: 'default' },
disputed: { label: '争议中', tone: 'danger' },
arbitrated: { label: '已仲裁', tone: 'success' },
}
const checkoutStatus: Record<string, MobileStatus> = {
submitted: { label: '等待确认', tone: 'warning' },
countered: { label: '已修正', tone: 'warning' },
accepted: { label: '已接受', tone: 'success' },
disputed: { label: '争议中', tone: 'danger' },
settled: { label: '仲裁结案', tone: 'success' },
}
function read(map: Record<string, MobileStatus>, value?: string | null): MobileStatus {
if (!value) return { label: '—', tone: 'default' }
return map[value] ?? { label: value, tone: 'default' }
}
export function orderStatusMeta(value?: string | null) {
return read(orderStatus, value)
}
export function handoffStatusMeta(value?: string | null) {
return read(handoffStatus, value)
}
export function settlementStatusMeta(value?: string | null) {
return read(settlementStatus, value)
}
export function checkoutStatusMeta(value?: string | null) {
return read(checkoutStatus, value)
}
export function roleLabel(role?: string | null) {
if (role === 'owner') return '我出租的'
if (role === 'renter') return '我租的'
return '订单'
}
+89
View File
@@ -0,0 +1,89 @@
export interface UserOrderListItem {
id: number
order_no: string
listing_id: number
listing_no: string
role: 'owner' | 'renter' | string
title: string
server_region: string
login_platform: string
rental_days?: number
daily_loss_m?: number
display_amount_cent: number
deposit_amount_cent: number
deposit_waived_amount_cent: number
status: string
handoff_status: string
can_hide?: boolean
payment_deadline_at?: string
distribution_site_id?: number | null
created_at: string
}
export interface UserOrderPage {
items: UserOrderListItem[]
total: number
page: number
page_size: number
}
export interface UserCheckout {
id: number
status: string
round_count: number
max_rounds: number
content: string
consumable_amount_cent: number
coin_consumed_m: number
other_amount_cent: number
deposit_deduct_amount_cent: number
renter_refund_amount_cent?: number | null
owner_income_amount_cent?: number | null
shortfall_cent: number
overshoot_amount_cent: number
owner_adjustment_reason?: string
renter_confirmed_at?: string | null
created_at: string
updated_at: string
}
export interface UserActiveDispute {
id: number
type: string
status: string
initiator_type: string
}
export interface UserOrderDetail {
id: number
order_no: string
listing_id: number
listing_no: string
owner_id: number
renter_id: number
title: string
server_region: string
login_platform: string
price_role?: string
rented_at?: string | null
estimated_duration_hours: number
estimated_end_at?: string | null
display_amount_cent: number
rent_amount_cent?: number | null
owner_rent_amount_cent?: number | null
deposit_amount_cent: number
deposit_waived_amount_cent: number
platform_fee_cent?: number | null
status: string
handoff_status: string
handoff_mode: string
settlement_mode: string
settlement_status: string
refund_status?: string
refund_amount_cent: number
payment_deadline_at?: string | null
active_dispute?: UserActiveDispute | null
checkout?: UserCheckout | null
created_at: string
updated_at: string
}