feat: P1阶段完成 - 订单模块迁移与重构

## P1.3: 订单模块(orders)

### 完整迁移
- 迁移 API: orders.ts
- 迁移 Views: 5个页面(桌面3 + 移动2)
- 迁移 Composables: useOrderSnapshot.ts
- 更新所有导入路径到 shared/

### 核心重构:拆分 useOrderDetail.ts
原始文件405行,混合了订单、支付、结算、争议等多个领域

**拆分为3个独立 composables:**

1. **usePaymentPolling.ts** - 支付轮询
   - 职责:轮询查询支付状态直到完成
   - 功能:开始/停止轮询、检查支付状态、自动重载
   - 代码:~65行

2. **useSettlement.ts** - 结算流程
   - 职责:处理订单结算完整流程
   - 功能:提交/接受/反驳/确认结算、表单管理
   - 代码:~170行

3. **useOrderDetail.ts** - 核心订单(重构后)
   - 职责:订单核心流程,组合使用上述composables
   - 功能:加载、取消、支付、交接、收货、争议
   - 代码:~215行

**重构优势:**
- 职责清晰,单一职责原则
- 可复用,支付和结算逻辑可独立使用
- 易测试,每个composable独立可测
- 易维护,从405行拆分为3个文件

### 技术改进
- 建立清晰的模块边界和导出规范
- 避免循环依赖
- 提高代码可测试性和可维护性

## 里程碑

🎉 **P1 阶段完成!**

-  P0: 基础设施(shared/)- 22个文件
-  P1.1: 钱包模块 - 5个文件
-  P1.2: 聊天模块 - 8个文件
-  P1.3: 订单模块 - 11个文件

**总计:** 3个核心业务模块,46个文件完成迁移

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
yml2213
2026-06-04 08:45:31 +08:00
co-authored by Claude Opus 4.7
parent b5903a169f
commit 125d83f2f2
13 changed files with 5075 additions and 146 deletions
+244
View File
@@ -0,0 +1,244 @@
import { apiClient } from '@/shared/api/client'
import type { ApiResponse } from '@/shared/types/types'
import type { HandoffStatus, OrderStatus, SettlementStatus } from '@/shared/types/status'
export interface Order {
id: number
order_no: string
listing_id: number
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
price_role?: 'renter' | 'owner' | 'admin' | string
display_amount: number
rent_amount?: number
owner_rent_amount?: number
deposit_amount: number
platform_fee?: number
account_snapshot?: Record<string, unknown>
status: OrderStatus
handoff_status: HandoffStatus
settlement_status: SettlementStatus
checkout?: Checkout
created_at: string
updated_at: string
}
export interface Checkout {
id: number
order_id: number
initiated_by: number
status: SettlementStatus
price_role?: 'renter' | 'owner' | 'admin' | string
display_amount: number
rent_amount?: number
owner_rent_amount?: number
platform_fee?: number
deposit_amount: number
consumable_amount: number
coin_consumed_m: 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
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 PayOrderResult {
paid: boolean
}
export interface SubmitCheckoutPayload {
content: string
consumable_amount: number
coin_consumed_m: number
other_amount: number
evidence_urls: string[]
}
export interface CounterCheckoutPayload {
consumable_amount: number
coin_consumed_m: number
other_amount: number
deposit_deduct_amount: number
reason: string
evidence_urls: string[]
}
export async function createOrder(listingId: number) {
const { data } = await apiClient.post<ApiResponse<Order>>('/orders', {
listing_id: listingId,
})
return data.data
}
export async function payOrder(id: number) {
const { data } = await apiClient.post<ApiResponse<PayOrderResult>>(`/orders/${id}/pay`)
return data.data
}
export async function fetchOrders() {
const { data } = await apiClient.get<ApiResponse<{ items: Order[] }>>('/orders')
return data.data.items
}
export async function fetchAdminOrders() {
const { data } = await apiClient.get<ApiResponse<{ items: Order[] }>>('/admin/orders')
return 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 fetchAdminOrder(id: string | number) {
const { data } = await apiClient.get<ApiResponse<Order>>(`/admin/orders/${id}`)
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 fetchHandoffRecords(id: string | number) {
const { data } = await apiClient.get<ApiResponse<{ items: HandoffRecord[] }>>(`/orders/${id}/handoff-records`)
return data.data.items
}
export async function fetchAdminHandoffRecords(id: string | number) {
const { data } = await apiClient.get<ApiResponse<{ items: HandoffRecord[] }>>(`/admin/orders/${id}/handoff-records`)
return data.data.items
}
export async function adminCloseOrder(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<{ closed: boolean }>>(`/admin/orders/${id}/close`, { reason })
return data.data
}
export async function adminMarkOrderAbnormal(id: number, reason: string) {
const { data } = await apiClient.post<ApiResponse<{ abnormal: boolean }>>(`/admin/orders/${id}/mark-abnormal`, { reason })
return data.data
}
export interface RefundStatus {
order_id: number
order_no: string
refund_status: string
refund_amount_cent: number
refunded_at?: string
total_amount: number
}
export async function adminRefundOrder(id: number) {
const { data } = await apiClient.post<ApiResponse<RefundStatus>>(`/admin/orders/${id}/refund`)
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 interface StartOrderPaymentRequest {
pay_way?: string
jspay_flag?: string
}
export async function startOrderPayment(orderId: number, req?: StartOrderPaymentRequest) {
const { data } = await apiClient.post<ApiResponse<PaymentOrder>>(`/orders/${orderId}/start-payment`, req || {})
return data.data
}
export async function queryOrderPayment(orderId: number) {
const { data } = await apiClient.get<ApiResponse<PaymentOrder>>(`/orders/${orderId}/query-payment`)
return data.data
}
export async function confirmReceive(id: number) {
const { data } = await apiClient.post<ApiResponse<{ received: boolean }>>(`/orders/${id}/confirm-receive`)
return data.data
}
export async function submitReturn(id: number, content: string) {
const { data } = await apiClient.post<ApiResponse<HandoffRecord>>(`/orders/${id}/return`, { content })
return data.data
}
export async function confirmReturn(id: number) {
const { data } = await apiClient.post<ApiResponse<{ completed: boolean }>>(`/orders/${id}/confirm-return`)
return data.data
}
export async function submitCheckout(id: number, payload: SubmitCheckoutPayload) {
const { data } = await apiClient.post<ApiResponse<HandoffRecord>>(`/orders/${id}/checkout`, payload)
return data.data
}
export async function confirmCheckout(id: number) {
const { data } = await apiClient.post<ApiResponse<{ completed: boolean }>>(`/orders/${id}/checkout/confirm`)
return data.data
}
export async function counterCheckout(id: number, payload: CounterCheckoutPayload) {
const { data } = await apiClient.post<ApiResponse<Checkout>>(`/orders/${id}/checkout/counter`, payload)
return data.data
}
export async function acceptCheckout(id: number) {
const { data } = await apiClient.post<ApiResponse<{ completed: boolean }>>(`/orders/${id}/checkout/accept`)
return data.data
}