优化:限价单份额显示单位更改
This commit is contained in:
parent
df82732fad
commit
fffd7461df
23
docs/api/order.md
Normal file
23
docs/api/order.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# order.ts
|
||||||
|
|
||||||
|
**路径**:`src/api/order.ts`
|
||||||
|
|
||||||
|
## 功能用途
|
||||||
|
|
||||||
|
订单相关 API:获取订单列表、取消订单,以及将 `ClobOrderItem` 映射为展示项(History、Open Orders)。
|
||||||
|
|
||||||
|
## 使用方式
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { getOrderList, mapOrderToOpenOrderItem, mapOrderToHistoryItem, cancelOrder } from '@/api/order'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据单位约定
|
||||||
|
|
||||||
|
- **price**:整数,已乘 10000(bps),`priceCents = price / 100`
|
||||||
|
- **originalSize / sizeMatched**:按 6 位小数传(1_000_000 = 1 share),展示时除以 `ORDER_SIZE_SCALE` 转为实际份额
|
||||||
|
|
||||||
|
## 扩展方式
|
||||||
|
|
||||||
|
1. 新增订单状态或筛选参数时,更新 `GetOrderListParams` 与 `getOrderList`
|
||||||
|
2. 展示格式变更时,调整 `mapOrderToOpenOrderItem`、`mapOrderToHistoryItem` 的格式化逻辑
|
||||||
@ -126,6 +126,9 @@ export interface HistoryDisplayItem {
|
|||||||
/** Side: Buy=1, Sell=2 */
|
/** Side: Buy=1, Sell=2 */
|
||||||
const Side = { Buy: 1, Sell: 2 } as const
|
const Side = { Buy: 1, Sell: 2 } as const
|
||||||
|
|
||||||
|
/** 订单份额接口按 6 位小数传(1_000_000 = 1 share),需除以该系数转为展示值 */
|
||||||
|
const ORDER_SIZE_SCALE = 1_000_000
|
||||||
|
|
||||||
function formatTimeAgo(createdAt: string | undefined): string {
|
function formatTimeAgo(createdAt: string | undefined): string {
|
||||||
if (!createdAt) return ''
|
if (!createdAt) return ''
|
||||||
const d = new Date(createdAt)
|
const d = new Date(createdAt)
|
||||||
@ -140,7 +143,7 @@ function formatTimeAgo(createdAt: string | undefined): string {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 ClobOrderItem 映射为钱包 History 展示项
|
* 将 ClobOrderItem 映射为钱包 History 展示项
|
||||||
* price 为整数(已乘 10000),sizeMatched 为已成交份额
|
* price 为整数(已乘 10000),size 按 6 位小数传(1_000_000 = 1 share)
|
||||||
*/
|
*/
|
||||||
export function mapOrderToHistoryItem(order: ClobOrderItem): HistoryDisplayItem {
|
export function mapOrderToHistoryItem(order: ClobOrderItem): HistoryDisplayItem {
|
||||||
const id = String(order.ID ?? '')
|
const id = String(order.ID ?? '')
|
||||||
@ -151,11 +154,12 @@ export function mapOrderToHistoryItem(order: ClobOrderItem): HistoryDisplayItem
|
|||||||
const activity = `${sideLabel} ${outcome}`
|
const activity = `${sideLabel} ${outcome}`
|
||||||
const priceBps = order.price ?? 0
|
const priceBps = order.price ?? 0
|
||||||
const priceCents = Math.round(priceBps / 100)
|
const priceCents = Math.round(priceBps / 100)
|
||||||
const size = order.sizeMatched ?? order.originalSize ?? 0
|
const sizeRaw = order.sizeMatched ?? order.originalSize ?? 0
|
||||||
|
const size = sizeRaw / ORDER_SIZE_SCALE
|
||||||
const valueUsd = (priceBps / 10000) * size
|
const valueUsd = (priceBps / 10000) * size
|
||||||
const value = `$${valueUsd.toFixed(2)}`
|
const value = `$${valueUsd.toFixed(2)}`
|
||||||
const verb = sideNum === Side.Sell ? 'Sold' : 'Bought'
|
const verb = sideNum === Side.Sell ? 'Sold' : 'Bought'
|
||||||
const activityDetail = `${verb} ${size} ${outcome} at ${priceCents}¢`
|
const activityDetail = `${verb} ${Math.floor(size)} ${outcome} at ${priceCents}¢`
|
||||||
const avgPrice = `${priceCents}¢`
|
const avgPrice = `${priceCents}¢`
|
||||||
const timeAgo = formatTimeAgo(order.createdAt)
|
const timeAgo = formatTimeAgo(order.createdAt)
|
||||||
return {
|
return {
|
||||||
@ -169,7 +173,7 @@ export function mapOrderToHistoryItem(order: ClobOrderItem): HistoryDisplayItem
|
|||||||
profitLossNegative: false,
|
profitLossNegative: false,
|
||||||
timeAgo,
|
timeAgo,
|
||||||
avgPrice,
|
avgPrice,
|
||||||
shares: String(size),
|
shares: String(Math.floor(size)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +198,7 @@ const OrderType = { GTC: 0, GTD: 1 } as const
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 ClobOrderItem 映射为钱包 Open Orders 展示项(未成交订单)
|
* 将 ClobOrderItem 映射为钱包 Open Orders 展示项(未成交订单)
|
||||||
* price 为整数(已乘 10000)
|
* price 为整数(已乘 10000),originalSize/sizeMatched 按 6 位小数传(1_000_000 = 1 share)
|
||||||
*/
|
*/
|
||||||
export function mapOrderToOpenOrderItem(order: ClobOrderItem): OpenOrderDisplayItem {
|
export function mapOrderToOpenOrderItem(order: ClobOrderItem): OpenOrderDisplayItem {
|
||||||
const id = String(order.ID ?? '')
|
const id = String(order.ID ?? '')
|
||||||
@ -205,9 +209,11 @@ export function mapOrderToOpenOrderItem(order: ClobOrderItem): OpenOrderDisplayI
|
|||||||
const priceBps = order.price ?? 0
|
const priceBps = order.price ?? 0
|
||||||
const priceCents = Math.round(priceBps / 100)
|
const priceCents = Math.round(priceBps / 100)
|
||||||
const price = `${priceCents}¢`
|
const price = `${priceCents}¢`
|
||||||
const originalSize = order.originalSize ?? 0
|
const originalSizeRaw = order.originalSize ?? 0
|
||||||
const sizeMatched = order.sizeMatched ?? 0
|
const sizeMatchedRaw = order.sizeMatched ?? 0
|
||||||
const filled = `${sizeMatched}/${originalSize}`
|
const originalSize = originalSizeRaw / ORDER_SIZE_SCALE
|
||||||
|
const sizeMatched = sizeMatchedRaw / ORDER_SIZE_SCALE
|
||||||
|
const filled = `${Math.floor(sizeMatched)}/${Math.floor(originalSize)}`
|
||||||
const totalUsd = (priceBps / 10000) * originalSize
|
const totalUsd = (priceBps / 10000) * originalSize
|
||||||
const total = `$${totalUsd.toFixed(2)}`
|
const total = `$${totalUsd.toFixed(2)}`
|
||||||
const expiration =
|
const expiration =
|
||||||
|
|||||||
@ -248,6 +248,8 @@ const tradeInitialOption = ref<'yes' | 'no' | undefined>(undefined)
|
|||||||
const tradeSheetOpen = ref(false)
|
const tradeSheetOpen = ref(false)
|
||||||
/** 控制底部栏内 TradeComponent 的渲染,延迟挂载以避免 slot 竞态警告 */
|
/** 控制底部栏内 TradeComponent 的渲染,延迟挂载以避免 slot 竞态警告 */
|
||||||
const tradeSheetRenderContent = ref(false)
|
const tradeSheetRenderContent = ref(false)
|
||||||
|
/** 从三点菜单点击 Merge/Split 时待打开的弹窗,等 TradeComponent 挂载后执行 */
|
||||||
|
const pendingMergeSplitDialog = ref<'merge' | 'split' | null>(null)
|
||||||
/** 移动端底部栏三点菜单开关 */
|
/** 移动端底部栏三点菜单开关 */
|
||||||
const mobileMenuOpen = ref(false)
|
const mobileMenuOpen = ref(false)
|
||||||
/** TradeComponent 引用,用于从底部栏触发 Merge/Split */
|
/** TradeComponent 引用,用于从底部栏触发 Merge/Split */
|
||||||
@ -583,19 +585,15 @@ function openSheetWithOption(side: 'yes' | 'no') {
|
|||||||
/** 从底部栏三点菜单打开 Merge 弹窗 */
|
/** 从底部栏三点菜单打开 Merge 弹窗 */
|
||||||
function openMergeFromBar() {
|
function openMergeFromBar() {
|
||||||
mobileMenuOpen.value = false
|
mobileMenuOpen.value = false
|
||||||
|
pendingMergeSplitDialog.value = 'merge'
|
||||||
tradeSheetOpen.value = true
|
tradeSheetOpen.value = true
|
||||||
nextTick(() => {
|
|
||||||
tradeComponentRef.value?.openMergeDialog?.()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 从底部栏三点菜单打开 Split 弹窗 */
|
/** 从底部栏三点菜单打开 Split 弹窗 */
|
||||||
function openSplitFromBar() {
|
function openSplitFromBar() {
|
||||||
mobileMenuOpen.value = false
|
mobileMenuOpen.value = false
|
||||||
|
pendingMergeSplitDialog.value = 'split'
|
||||||
tradeSheetOpen.value = true
|
tradeSheetOpen.value = true
|
||||||
nextTick(() => {
|
|
||||||
tradeComponentRef.value?.openSplitDialog?.()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTradeSubmit(payload: {
|
function onTradeSubmit(payload: {
|
||||||
@ -729,8 +727,19 @@ watch(tradeSheetOpen, (open) => {
|
|||||||
tradeSheetMountTimer = setTimeout(() => {
|
tradeSheetMountTimer = setTimeout(() => {
|
||||||
tradeSheetRenderContent.value = true
|
tradeSheetRenderContent.value = true
|
||||||
tradeSheetMountTimer = undefined
|
tradeSheetMountTimer = undefined
|
||||||
|
nextTick(() => {
|
||||||
|
const pending = pendingMergeSplitDialog.value
|
||||||
|
if (pending === 'merge') {
|
||||||
|
pendingMergeSplitDialog.value = null
|
||||||
|
tradeComponentRef.value?.openMergeDialog?.()
|
||||||
|
} else if (pending === 'split') {
|
||||||
|
pendingMergeSplitDialog.value = null
|
||||||
|
tradeComponentRef.value?.openSplitDialog?.()
|
||||||
|
}
|
||||||
|
})
|
||||||
}, 50)
|
}, 50)
|
||||||
} else {
|
} else {
|
||||||
|
pendingMergeSplitDialog.value = null
|
||||||
if (tradeSheetMountTimer) {
|
if (tradeSheetMountTimer) {
|
||||||
clearTimeout(tradeSheetMountTimer)
|
clearTimeout(tradeSheetMountTimer)
|
||||||
tradeSheetMountTimer = undefined
|
tradeSheetMountTimer = undefined
|
||||||
|
|||||||
@ -743,6 +743,8 @@ const tradeInitialTabFromBar = ref<'buy' | 'sell' | undefined>(undefined)
|
|||||||
const tradeSheetOpen = ref(false)
|
const tradeSheetOpen = ref(false)
|
||||||
/** 控制底部栏内 TradeComponent 的渲染,延迟挂载以避免 slot 竞态警告 */
|
/** 控制底部栏内 TradeComponent 的渲染,延迟挂载以避免 slot 竞态警告 */
|
||||||
const tradeSheetRenderContent = ref(false)
|
const tradeSheetRenderContent = ref(false)
|
||||||
|
/** 从三点菜单点击 Merge/Split 时待打开的弹窗,等 TradeComponent 挂载后执行 */
|
||||||
|
const pendingMergeSplitDialog = ref<'merge' | 'split' | null>(null)
|
||||||
/** 从持仓 Sell 打开的弹窗 */
|
/** 从持仓 Sell 打开的弹窗 */
|
||||||
const sellDialogOpen = ref(false)
|
const sellDialogOpen = ref(false)
|
||||||
/** 控制 Sell 弹窗内 TradeComponent 的渲染,延迟卸载以避免 emitsOptions 竞态 */
|
/** 控制 Sell 弹窗内 TradeComponent 的渲染,延迟卸载以避免 emitsOptions 竞态 */
|
||||||
@ -773,18 +775,14 @@ function openSheetWithOption(side: 'yes' | 'no') {
|
|||||||
|
|
||||||
function openMergeFromBar() {
|
function openMergeFromBar() {
|
||||||
mobileMenuOpen.value = false
|
mobileMenuOpen.value = false
|
||||||
|
pendingMergeSplitDialog.value = 'merge'
|
||||||
tradeSheetOpen.value = true
|
tradeSheetOpen.value = true
|
||||||
nextTick(() => {
|
|
||||||
mobileTradeComponentRef.value?.openMergeDialog?.()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSplitFromBar() {
|
function openSplitFromBar() {
|
||||||
mobileMenuOpen.value = false
|
mobileMenuOpen.value = false
|
||||||
|
pendingMergeSplitDialog.value = 'split'
|
||||||
tradeSheetOpen.value = true
|
tradeSheetOpen.value = true
|
||||||
nextTick(() => {
|
|
||||||
mobileTradeComponentRef.value?.openSplitDialog?.()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const toastStore = useToastStore()
|
const toastStore = useToastStore()
|
||||||
@ -863,8 +861,19 @@ watch(tradeSheetOpen, (open) => {
|
|||||||
tradeSheetMountTimer = setTimeout(() => {
|
tradeSheetMountTimer = setTimeout(() => {
|
||||||
tradeSheetRenderContent.value = true
|
tradeSheetRenderContent.value = true
|
||||||
tradeSheetMountTimer = undefined
|
tradeSheetMountTimer = undefined
|
||||||
|
nextTick(() => {
|
||||||
|
const pending = pendingMergeSplitDialog.value
|
||||||
|
if (pending === 'merge') {
|
||||||
|
pendingMergeSplitDialog.value = null
|
||||||
|
mobileTradeComponentRef.value?.openMergeDialog?.()
|
||||||
|
} else if (pending === 'split') {
|
||||||
|
pendingMergeSplitDialog.value = null
|
||||||
|
mobileTradeComponentRef.value?.openSplitDialog?.()
|
||||||
|
}
|
||||||
|
})
|
||||||
}, 50)
|
}, 50)
|
||||||
} else {
|
} else {
|
||||||
|
pendingMergeSplitDialog.value = null
|
||||||
if (tradeSheetMountTimer) {
|
if (tradeSheetMountTimer) {
|
||||||
clearTimeout(tradeSheetMountTimer)
|
clearTimeout(tradeSheetMountTimer)
|
||||||
tradeSheetMountTimer = undefined
|
tradeSheetMountTimer = undefined
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user