import { get, post } from './request' /** 分页结果 */ export interface PageResult { list: T[] page: number pageSize: number total: number } /** * 订单项(与 doc.json definitions["model.ClobOrder"] 对齐) * GET /clob/order/getOrderList 列表项 */ export interface ClobOrderItem { ID: number assetID?: string createdAt?: string updatedAt?: string expiration?: number feeRateBps?: number market?: string orderType?: number originalSize?: number outcome?: string price?: number side?: number sizeMatched?: number status?: number userID?: number [key: string]: unknown } /** 订单列表响应 */ export interface OrderListResponse { code: number data: PageResult msg: string } /** 订单状态:1=未成交(Live),2=已成交,0=已取消等 */ export const OrderStatus = { Live: 1, Matched: 2, Cancelled: 0, } as const /** * GET /clob/order/getOrderList 请求参数 */ export interface GetOrderListParams { page?: number pageSize?: number /** 订单状态筛选:1=未成交 */ status?: number startCreatedAt?: string endCreatedAt?: string marketID?: string tokenID?: string userID?: number } /** * 分页获取订单列表 * GET /clob/order/getOrderList * 需鉴权:x-token、x-user-id */ export async function getOrderList( params: GetOrderListParams = {}, config?: { headers?: Record }, ): Promise { const { page = 1, pageSize = 10, status, startCreatedAt, endCreatedAt, marketID, tokenID, userID } = params const query: Record = { page, pageSize } if (status != null && Number.isFinite(status)) query.status = status if (startCreatedAt != null && startCreatedAt !== '') query.startCreatedAt = startCreatedAt if (endCreatedAt != null && endCreatedAt !== '') query.endCreatedAt = endCreatedAt if (marketID != null && marketID !== '') query.marketID = marketID if (tokenID != null && tokenID !== '') query.tokenID = tokenID if (userID != null && Number.isFinite(userID)) query.userID = userID return get('/clob/order/getOrderList', query, config) } /** 取消订单请求体(request.CancelOrderReq) */ export interface CancelOrderReq { orderID: number tokenID: string userID: number } /** 通用 API 响应 */ export interface ApiResponse { code: number data?: unknown msg: string } /** * POST /clob/order/cancelOrder * 撤销订单(撮合引擎),需鉴权 x-token */ export async function cancelOrder( data: CancelOrderReq, config?: { headers?: Record }, ): Promise { return post('/clob/order/cancelOrder', data, config) } /** 钱包 History 展示项(与 Wallet.vue HistoryItem 一致) */ export interface HistoryDisplayItem { id: string market: string side: 'Yes' | 'No' activity: string value: string activityDetail?: string profitLoss?: string profitLossNegative?: boolean timeAgo?: string avgPrice?: string shares?: string iconChar?: string iconClass?: string } /** Side: Buy=1, Sell=2 */ const Side = { Buy: 1, Sell: 2 } as const function formatTimeAgo(createdAt: string | undefined): string { if (!createdAt) return '' const d = new Date(createdAt) const now = Date.now() const diff = now - d.getTime() if (diff < 60000) return 'Just now' if (diff < 3600000) return `${Math.floor(diff / 60000)} minutes ago` if (diff < 86400000) return `${Math.floor(diff / 3600000)} hours ago` if (diff < 604800000) return `${Math.floor(diff / 86400000)} days ago` return d.toLocaleDateString() } /** * 将 ClobOrderItem 映射为钱包 History 展示项 * price 为整数(已乘 10000),sizeMatched 为已成交份额 */ export function mapOrderToHistoryItem(order: ClobOrderItem): HistoryDisplayItem { const id = String(order.ID ?? '') const market = order.market ?? '' const outcome = order.outcome ?? 'Yes' const sideNum = order.side ?? Side.Buy const sideLabel = sideNum === Side.Sell ? 'Sell' : 'Buy' const activity = `${sideLabel} ${outcome}` const priceBps = order.price ?? 0 const priceCents = Math.round(priceBps / 100) const size = order.sizeMatched ?? order.originalSize ?? 0 const valueUsd = (priceBps / 10000) * size const value = `$${valueUsd.toFixed(2)}` const verb = sideNum === Side.Sell ? 'Sold' : 'Bought' const activityDetail = `${verb} ${size} ${outcome} at ${priceCents}¢` const avgPrice = `${priceCents}¢` const timeAgo = formatTimeAgo(order.createdAt) return { id, market, side: outcome === 'No' ? 'No' : 'Yes', activity, value, activityDetail, profitLoss: value, profitLossNegative: false, timeAgo, avgPrice, shares: String(size), } } /** 钱包 Open Orders 展示项(与 Wallet.vue OpenOrder 一致) */ export interface OpenOrderDisplayItem { id: string market: string side: 'Yes' | 'No' outcome: string price: string filled: string total: string expiration: string actionLabel?: string filledDisplay?: string orderID?: number tokenID?: string } /** OrderType GTC=0 表示 Until Cancelled */ const OrderType = { GTC: 0, GTD: 1 } as const /** * 将 ClobOrderItem 映射为钱包 Open Orders 展示项(未成交订单) * price 为整数(已乘 10000) */ export function mapOrderToOpenOrderItem(order: ClobOrderItem): OpenOrderDisplayItem { const id = String(order.ID ?? '') const market = order.market ?? '' const sideNum = order.side ?? Side.Buy const side = sideNum === Side.Sell ? 'No' : 'Yes' const outcome = order.outcome || (side === 'Yes' ? 'Yes' : 'No') const priceBps = order.price ?? 0 const priceCents = Math.round(priceBps / 100) const price = `${priceCents}¢` const originalSize = order.originalSize ?? 0 const sizeMatched = order.sizeMatched ?? 0 const filled = `${sizeMatched}/${originalSize}` const totalUsd = (priceBps / 10000) * originalSize const total = `$${totalUsd.toFixed(2)}` const expiration = order.orderType === OrderType.GTC ? 'Until Cancelled' : order.expiration?.toString() ?? '' const actionLabel = sideNum === Side.Buy ? `Buy ${outcome}` : `Sell ${outcome}` return { id, market, side, outcome, price, filled, total, expiration, actionLabel, filledDisplay: filled, orderID: order.ID, tokenID: order.assetID, } }