Files
hfb_sys/frontend/src/features/orders/api/orders.ts
T

480 lines
13 KiB
TypeScript

import { apiClient } from '@/shared/api/client'
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
order_no: string
listing_id: number
listing_no: string
account_id: number
owner_id: number
renter_id: number
owner_phone?: string
renter_phone?: string
title: string
server_region: string
login_platform: string
rented_at?: string
estimated_duration_hours: number
estimated_end_at?: string
price_role?: 'renter' | 'owner' | 'admin' | string
display_amount_cent: number
rent_amount_cent?: number
owner_rent_amount_cent?: number
deposit_amount_cent: number
deposit_original_amount_cent: number
deposit_waived_amount_cent: number
platform_fee_cent?: number
account_snapshot?: Record<string, unknown>
listing_snapshot?: string
checkout_info?: string
counter_info?: string
status: OrderStatus
handoff_status: HandoffStatus
handoff_mode?: string
settlement_mode?: string
managed_admin_id?: number
settlement_status: SettlementStatus
offline_settlement_status?: string
offline_settlement_amount_cent?: number
offline_settlement_remark?: string
offline_settled_by?: number
offline_settled_at?: string
refund_status?: string
refund_amount_cent?: number
deposit_hold_status?: string
deposit_hold_amount_cent?: number
deposit_hold_reason?: string
deposit_held_at?: string
deposit_hold_released_at?: string
active_dispute?: ActiveDispute
checkout?: Checkout
admin_actions?: AdminActions
payment_deadline_at?: string
created_at: string
updated_at: string
}
export interface AdminActions {
reset_handoff?: AdminAction
platform_handoff?: AdminAction
platform_checkout_confirm?: AdminAction
platform_checkout_counter?: AdminAction
platform_checkout_dispute?: AdminAction
platform_offline_settlement?: AdminAction
}
export interface AdminAction {
enabled: boolean
label: string
}
export interface ActiveDispute {
id: number
initiator_id: number
initiator_type?: 'user' | 'admin' | string
initiator_admin_id?: number
type: string
status: string
}
export interface Checkout {
id: number
order_id: number
initiated_by: number
status: SettlementStatus
round_count?: number
turn?: 'owner' | 'renter' | string
proposed_by?: number
max_rounds?: number
can_counter?: boolean
can_accept?: boolean
price_role?: 'renter' | 'owner' | 'admin' | string
display_amount_cent: number
rent_amount_cent?: number
owner_rent_amount_cent?: number
platform_fee_cent?: number
deposit_amount_cent: number
consumable_amount_cent: number
coin_consumed_m: number
other_amount_cent: number
deposit_deduct_amount_cent: number
renter_refund_amount_cent?: number
owner_income_amount_cent?: number
shortfall_cent?: number
overshoot_amount_cent?: number
content: string
evidence_urls: string[]
owner_adjustment_reason: string
owner_adjusted_at?: string
renter_confirmed_at?: string
renter_rejected_at?: string
created_at: string
updated_at: string
}
export interface HandoffRecord {
id: number
order_id: number
from_user_id: number
to_user_id: number
type: string
content: string
confirmed_by_renter_at?: string
confirmed_by_owner_at?: string
created_at: string
}
export interface PaymentOrder {
id: number
payment_no: string
order_id: number
order_no: string
provider: string
third_order_id: string
provider_order_id: string
pay_way: string
jspay_flag: string
amount_cent: number
status: string
td_code?: string
jspay_url?: string
jspay_info?: string
paid: boolean
paid_at?: string
created_at: string
updated_at: string
}
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
consumableAmountYuan?: number
coin_consumed_m: number
otherAmountYuan?: number
depositDeductAmountYuan?: number
evidence_urls: string[]
reason?: string
}
export interface AdminOrderQuery {
keyword?: string
status?: string
handoff_status?: string
settlement_status?: 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 type PaymentPayWay = 'ZFBZF' | 'WXZF'
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.consumableAmountYuan),
coin_consumed_m: payload.coin_consumed_m,
other_amount_cent: yuanToCent(payload.otherAmountYuan),
deposit_deduct_amount_cent: yuanToCent(payload.depositDeductAmountYuan),
evidence_urls: payload.evidence_urls,
reason: payload.reason,
}
}
export async function fetchOrderAgreements() {
const { data } = await apiClient.get<ApiResponse<OrderAgreements>>('/order-agreements')
return data.data
}
export async function fetchPostRentalNotice() {
const { data } = await apiClient.get<ApiResponse<PostRentalNotice>>('/post-rental-notice')
return data.data
}
export async function fetchOrders() {
const { data } = await apiClient.get<ApiResponse<{ items: Order[] }>>('/orders')
return Array.isArray(data.data?.items) ? data.data.items : []
}
export async function fetchOrder(id: string | number) {
const { data } = await apiClient.get<ApiResponse<Order>>(`/orders/${id}`)
return data.data
}
export async function createOrder(listingId: number) {
const { data } = await apiClient.post<ApiResponse<Order>>('/orders', { listing_id: listingId })
return data.data
}
export async function cancelOrder(id: number) {
const { data } = await apiClient.post<ApiResponse<{ cancelled: boolean }>>(`/orders/${id}/cancel`)
return data.data
}
export async function submitHandoff(id: number, content: string) {
const { data } = await apiClient.post<ApiResponse<HandoffRecord>>(`/orders/${id}/handoff`, {
content,
})
return data.data
}
export async function confirmHandoff(orderId: number, type: string, content: string) {
const { data } = await apiClient.post<ApiResponse<{ confirmed: boolean }>>(
`/orders/${orderId}/handoff/${type}/confirm`,
{ content }
)
return data.data
}
export async function fetchHandoffRecords(id: string | number) {
const { data } = await apiClient.get<ApiResponse<{ items: HandoffRecord[] }>>(
`/orders/${id}/handoff-records`
)
return Array.isArray(data.data?.items) ? data.data.items : []
}
export async function confirmReceive(id: number) {
const { data } = await apiClient.post<ApiResponse<{ confirmed: boolean }>>(
`/orders/${id}/confirm-receive`
)
return data.data
}
export async function startOrderPayment(orderId: number, req: StartOrderPaymentRequest = {}) {
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(
`/orders/${orderId}/start-payment`,
{
pay_way: req.pay_way || 'ZFBZF',
jspay_flag: req.jspay_flag || '',
}
)
return data.data
}
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.get<ApiResponse<PaymentOrder>>(
`/orders/${orderId}/query-payment`
)
return data.data
}
export function queryPayment(orderId: number) {
return queryOrderPayment(orderId)
}
export async function submitCheckout(id: number, payload: SubmitCheckoutPayload) {
const { data } = await apiClient.post<ApiResponse<Checkout>>(
`/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<ApiResponse<{ confirmed: boolean }>>(
`/orders/${id}/checkout/confirm`
)
return data.data
}
export async function acceptCheckout(id: number) {
const { data } = await apiClient.post<ApiResponse<{ accepted: boolean }>>(
`/orders/${id}/checkout/accept`
)
return data.data
}
export async function rejectCheckout(id: number) {
const { data } = await apiClient.post<ApiResponse<{ rejected: boolean }>>(
`/orders/${id}/checkout/reject`
)
return data.data
}
export async function counterCheckout(id: number, payload: SubmitCheckoutPayload) {
const { data } = await apiClient.post<ApiResponse<Checkout>>(
`/orders/${id}/checkout/counter`,
toCheckoutRequest(payload)
)
return data.data
}
export async function fetchAdminOrders(page = 1, pageSize = 20, query: AdminOrderQuery = {}) {
const { data } = await apiClient.get<ApiResponse<PaginatedResult<Order>>>('/admin/orders', {
params: { page, page_size: pageSize, ...query },
})
return data.data
}
export async function fetchAdminOrder(id: string | number) {
const { data } = await apiClient.get<ApiResponse<Order>>(`/admin/orders/${id}`)
return data.data
}
export async function fetchAdminLatestOrderByListing(listingId: string | number) {
const { data } = await apiClient.get<ApiResponse<Order>>(
`/admin/listing-orders/${listingId}/latest`
)
return data.data
}
export async function fetchAdminHandoffRecords(id: string | number) {
const { data } = await apiClient.get<ApiResponse<{ items: HandoffRecord[] }>>(
`/admin/orders/${id}/handoff-records`
)
return Array.isArray(data.data?.items) ? data.data.items : []
}
export async function adminCloseOrder(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<Order>>(`/admin/orders/${id}/close`, { reason })
return data.data
}
export async function adminSealOrder(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<Order>>(`/admin/orders/${id}/seal`, { reason })
return data.data
}
export async function adminMarkOrderAbnormal(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<Order>>(`/admin/orders/${id}/mark-abnormal`, {
reason,
})
return data.data
}
export async function adminResetHandoff(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<Order>>(`/admin/orders/${id}/reset-handoff`, {
reason,
})
return data.data
}
export async function adminPlatformHandoff(id: number, content: string, reason: string) {
const { data } = await apiClient.post<ApiResponse<HandoffRecord>>(
`/admin/orders/${id}/platform-handoff`,
{ content, reason }
)
return data.data
}
export async function adminPlatformCheckoutConfirm(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<{ confirmed: boolean }>>(
`/admin/orders/${id}/platform-checkout/confirm`,
{ reason }
)
return data.data
}
export async function adminPlatformCheckoutCounter(id: number, payload: SubmitCheckoutPayload) {
const { data } = await apiClient.post<ApiResponse<Checkout>>(
`/admin/orders/${id}/platform-checkout/counter`,
toCheckoutRequest(payload)
)
return data.data
}
export async function adminPlatformCheckoutDispute(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<{ disputed: boolean }>>(
`/admin/orders/${id}/platform-checkout/dispute`,
{ reason }
)
return data.data
}
export async function adminMarkOfflineSettlement(id: number, remark: string) {
const { data } = await apiClient.post<ApiResponse<{ settled: boolean }>>(
`/admin/orders/${id}/offline-settlement`,
{ remark }
)
return data.data
}
export async function adminRefundStatus(id: number) {
const { data } = await apiClient.get<ApiResponse<RefundStatus>>(
`/admin/orders/${id}/refund-status`
)
return data.data
}
export async function adminRefundOrder(id: number) {
const { data } = await apiClient.post<ApiResponse<RefundStatus>>(`/admin/orders/${id}/refund`)
return data.data
}
export async function adminApproveRefund(id: number) {
const { data } = await apiClient.post<ApiResponse<{ approved: boolean }>>(
`/admin/orders/${id}/refund/approve`
)
return data.data
}
export async function adminRejectRefund(id: number, action: 'restore' | 'close') {
const { data } = await apiClient.post<ApiResponse<{ rejected: boolean }>>(
`/admin/orders/${id}/refund/reject`,
{ action }
)
return data.data
}
export async function adminHoldDeposit(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<{ held: boolean }>>(
`/admin/orders/${id}/deposit-hold`,
{ reason }
)
return data.data
}
export async function adminReleaseDeposit(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<{ released: boolean }>>(
`/admin/orders/${id}/deposit-release`,
{ reason }
)
return data.data
}
export async function fetchPendingRefundOrders() {
const { data } = await apiClient.get<ApiResponse<{ items: Order[] }>>(
'/admin/orders/refund-pending'
)
return data.data.items
}