优化:增加模拟数据开关

This commit is contained in:
ivan 2026-02-26 16:10:20 +08:00
parent 4ab5ffa6af
commit ddca28e51c
10 changed files with 426 additions and 196 deletions

View File

@ -6,6 +6,14 @@
# WebSocket 路径前缀(可选)。若 CLOB WS 在 /api/clob/ws 且 API base 无 /api则设
# VITE_WS_PATH_PREFIX=/api
#
# 模拟数据开关(方便本地测试):
# VITE_USE_MOCK_DATA=true # 总开关:全部启用 mock
# VITE_USE_MOCK_DATA=false # 全部关闭 mock
# VITE_USE_MOCK_CATEGORY=true # 分类树用 mock
# VITE_USE_MOCK_EVENT=true # 事件接口失败时 mock 兜底(默认 true
# VITE_USE_MOCK_ORDER_BOOK=true # 订单簿无 CLOB 时用 mock默认 true
# VITE_USE_MOCK_WALLET=true # 钱包持仓/订单/历史用 mock默认 true
#
# 生产打包/部署时自动使用 .env.production 中的 https://api.xtrader.vip
# SSH 部署npm run deploy不配置时使用默认值

41
docs/api/mockData.md Normal file
View File

@ -0,0 +1,41 @@
# mockData.ts
**路径**`src/api/mockData.ts`
## 功能用途
模拟数据统一封装,集中管理事件、分类、订单簿、钱包等 mock 数据,配合 `src/config/mock.ts` 的开关使用。
## 导出内容
| 导出 | 类型 | 说明 |
|------|------|------|
| `MOCK_EVENT_LIST` | `PmEventListItem[]` | 模拟事件列表(来自 mockEventList |
| `MOCK_CATEGORY_TREE` | `CategoryTreeNode[]` | 模拟分类树(来自 category |
| `MOCK_ORDER_BOOK_ASKS` | `MockOrderBookRow[]` | 订单簿卖单 |
| `MOCK_ORDER_BOOK_BIDS` | `MockOrderBookRow[]` | 订单簿买单 |
| `MOCK_ORDER_BOOK_LAST_PRICE` | `number` | 最新价 |
| `MOCK_ORDER_BOOK_SPREAD` | `number` | 价差 |
| `MOCK_TOKEN_ID` | `string` | 测试用 token ID |
| `MOCK_WALLET_POSITIONS` | `MockPosition[]` | 钱包持仓 |
| `MOCK_WALLET_ORDERS` | `MockOpenOrder[]` | 钱包未成交订单 |
| `MOCK_WALLET_HISTORY` | `MockHistoryItem[]` | 钱包历史 |
| `getMockEventById(id)` | `(id: number) => PmEventListItem \| null` | 按 ID 获取 mock 事件 |
## 使用方式
```typescript
import { MOCK_WALLET_POSITIONS, getMockEventById } from '@/api/mockData'
import { USE_MOCK_WALLET } from '@/config/mock'
if (USE_MOCK_WALLET) {
positions.value = [...MOCK_WALLET_POSITIONS]
}
const fallback = getMockEventById(9001)
```
## 扩展方式
1. 新增 mock 数据:在 `mockData.ts` 中定义并导出
2. 修改现有数据:直接编辑对应常量

View File

@ -24,4 +24,4 @@ const cards = MOCK_EVENT_LIST.map(mapEventItemToCard)
## 扩展方式
1. **新增 mock 项**:在 `MOCK_EVENT_LIST` 中追加符合 `PmEventListItem` 结构的对象
2. **环境切换**:在 Home 等视图中根据 `import.meta.env.DEV` 选择使用 mock 或真实接口
2. **统一入口**`MOCK_EVENT_LIST` 已由 `src/api/mockData.ts` 统一导出,配合 `src/config/mock.ts``USE_MOCK_EVENT` 开关使用

37
docs/config/mock.md Normal file
View File

@ -0,0 +1,37 @@
# mock.ts
**路径**`src/config/mock.ts`
## 功能用途
模拟数据开关配置,通过环境变量控制各模块是否使用 mock 数据,方便本地测试与联调。
## 开关说明
| 变量 | 说明 | 默认值 |
|------|------|--------|
| `VITE_USE_MOCK_DATA` | 总开关:`true` 全部启用,`false` 全部关闭 | - |
| `VITE_USE_MOCK_CATEGORY` | 分类树Home 使用模拟分类 | false |
| `VITE_USE_MOCK_EVENT` | 事件EventMarkets 接口失败时 mock 兜底 | true |
| `VITE_USE_MOCK_ORDER_BOOK` | 订单簿:无 CLOB 数据时用 mock | true |
| `VITE_USE_MOCK_WALLET` | 钱包:持仓/订单/历史用 mock | true |
## 使用方式
`.env` 中配置:
```bash
# 全部启用 mock
VITE_USE_MOCK_DATA=true
# 全部关闭 mock联调真实接口时
VITE_USE_MOCK_DATA=false
# 仅分类树用 mock
VITE_USE_MOCK_CATEGORY=true
```
## 扩展方式
1. 新增模块开关:在 `mock.ts` 中增加 `USE_MOCK_XXX` 导出
2. 新增 mock 数据:在 `src/api/mockData.ts` 中补充并导出

262
src/api/mockData.ts Normal file
View File

@ -0,0 +1,262 @@
/**
*
* HomeEventMarketsOrderBookWallet 使
* src/config/mock.ts
*/
import type { PmEventListItem } from './event'
// --- 事件列表(来自 mockEventList ---
import { MOCK_EVENT_LIST } from './mockEventList'
export { MOCK_EVENT_LIST }
// --- 分类树(来自 category ---
export { MOCK_CATEGORY_TREE } from './category'
// --- 订单簿 mock ---
export interface MockOrderBookRow {
price: number
shares: number
}
export const MOCK_ORDER_BOOK_ASKS: MockOrderBookRow[] = [
{ price: 45, shares: 1000.0 },
{ price: 44, shares: 2500.0 },
{ price: 43, shares: 1800.0 },
{ price: 42, shares: 3200.0 },
{ price: 41, shares: 2000.0 },
{ price: 40, shares: 1500.0 },
{ price: 39, shares: 800.0 },
{ price: 38, shares: 500.0 },
{ price: 37, shares: 300.0 },
]
export const MOCK_ORDER_BOOK_BIDS: MockOrderBookRow[] = [
{ price: 36, shares: 200.0 },
{ price: 35, shares: 500.0 },
{ price: 34, shares: 1000.0 },
{ price: 33, shares: 1500.0 },
{ price: 32, shares: 2000.0 },
{ price: 31, shares: 2500.0 },
{ price: 30, shares: 3000.0 },
{ price: 29, shares: 2800.0 },
{ price: 28, shares: 2500.0 },
{ price: 27, shares: 2000.0 },
{ price: 26, shares: 1500.0 },
{ price: 25, shares: 1000.0 },
]
export const MOCK_ORDER_BOOK_LAST_PRICE = 37
export const MOCK_ORDER_BOOK_SPREAD = 1
// --- 钱包 mock ---
export const MOCK_TOKEN_ID =
'59966088656508531737144108943848781534186324373509174641856486864137458635937'
export interface MockPosition {
id: string
market: string
iconChar?: string
iconClass?: string
outcomeTag?: string
outcomePillClass?: string
shares: string
avgNow: string
bet: string
toWin: string
value: string
valueChange?: string
valueChangePct?: string
valueChangeLoss?: boolean
sellOutcome?: string
outcomeWord?: string
}
export interface MockOpenOrder {
id: string
market: string
side: 'Yes' | 'No'
outcome: string
price: string
filled: string
total: string
expiration: string
actionLabel?: string
filledDisplay?: string
iconChar?: string
iconClass?: string
orderID?: number
tokenID?: string
}
export interface MockHistoryItem {
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
}
export const MOCK_WALLET_POSITIONS: MockPosition[] = [
{
id: 'p1',
market: 'Bitcoin Up or Down - February 9, 2:00AM-2:15AM ET',
iconChar: '₿',
iconClass: 'position-icon-btc',
outcomeTag: 'Down 72¢',
outcomePillClass: 'pill-down',
shares: '6.9 shares',
avgNow: '72¢ → 0.5¢',
bet: '$4.95',
toWin: '$6.87',
value: '$0.03',
valueChange: '-$4.91',
valueChangePct: '99.31%',
valueChangeLoss: true,
sellOutcome: 'Down',
outcomeWord: 'Down',
},
{
id: 'p2',
market: 'Bitcoin Up or Down - February 9, 2:15AM-2:30AM ET',
iconChar: '₿',
iconClass: 'position-icon-btc',
outcomeTag: 'Up 26¢',
outcomePillClass: 'pill-yes',
shares: '3.8 shares',
avgNow: '28¢ → 26¢',
bet: '$0.99',
toWin: '$3.54',
value: '$0.90',
valueChange: '-$0.09',
valueChangePct: '8.9%',
valueChangeLoss: true,
sellOutcome: 'Up',
outcomeWord: 'Up',
},
{
id: 'p3',
market: 'Will ETH merge complete by Q3?',
iconChar: 'Ξ',
iconClass: 'position-icon-eth',
outcomeTag: 'Yes 48¢',
outcomePillClass: 'pill-yes',
shares: '30 shares',
avgNow: '45¢ → 48¢',
bet: '$30',
toWin: '$36',
value: '$32',
valueChange: '+$2',
valueChangePct: '6.67%',
valueChangeLoss: false,
sellOutcome: 'Yes',
outcomeWord: 'Yes',
},
]
export const MOCK_WALLET_ORDERS: MockOpenOrder[] = [
{
id: 'o1',
market: 'Bitcoin Up or Down - February 9, 2:45AM-3:00AM ET',
side: 'Yes',
outcome: 'Up',
price: '1¢',
filled: '0',
total: '$0.05',
expiration: 'Until Cancelled',
actionLabel: 'Buy Up',
filledDisplay: '0/5',
iconChar: '₿',
iconClass: 'position-icon-btc',
orderID: 5,
tokenID: MOCK_TOKEN_ID,
},
{
id: 'o2',
market: 'Will Bitcoin hit $100k by end of 2025?',
side: 'Yes',
outcome: 'Yes',
price: '70¢',
filled: '0',
total: '$70',
expiration: 'Dec 31, 2025',
orderID: 5,
tokenID: MOCK_TOKEN_ID,
},
{
id: 'o3',
market: 'Will ETH merge complete by Q3?',
side: 'No',
outcome: 'No',
price: '52¢',
filled: '25',
total: '$26',
expiration: 'Sep 30, 2025',
orderID: 5,
tokenID: MOCK_TOKEN_ID,
},
]
export const MOCK_WALLET_HISTORY: MockHistoryItem[] = [
{
id: 'h1',
market: 'Bitcoin Up or Down - February 9, 3:00AM-3:15AM ET',
side: 'No',
activity: 'Sell No',
activityDetail: 'Sold 1 Down at 50¢',
value: '$0.50',
profitLoss: '+$0.50',
profitLossNegative: false,
timeAgo: '3 minutes ago',
avgPrice: '50¢',
shares: '1',
iconChar: '₿',
iconClass: 'position-icon-btc',
},
{
id: 'h2',
market: 'Bitcoin Up or Down - February 9, 3:00AM-3:15AM ET',
side: 'Yes',
activity: 'Sell Yes',
activityDetail: 'Sold 1 Up at 63¢',
value: '$0.63',
profitLoss: '+$0.63',
profitLossNegative: false,
timeAgo: '6 minutes ago',
iconChar: '₿',
iconClass: 'position-icon-btc',
},
{
id: 'h3',
market: 'Bitcoin Up or Down - February 9, 3:00AM-3:15AM ET',
side: 'Yes',
activity: 'Split',
activityDetail: 'Split',
value: '-$1.00',
profitLoss: '-$1.00',
profitLossNegative: true,
timeAgo: '7 minutes ago',
iconChar: '₿',
iconClass: 'position-icon-btc',
},
{
id: 'h4',
market: 'Will ETH merge complete by Q3?',
side: 'No',
activity: 'Sell No',
value: '$35.20',
},
]
export function getMockEventById(id: number): PmEventListItem | null {
const item = MOCK_EVENT_LIST.find((e) => e.ID === id)
return item && (item.markets?.length ?? 0) > 1 ? item : null
}

View File

@ -82,6 +82,13 @@
import { ref, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import HorizontalProgressBar from './HorizontalProgressBar.vue'
import {
MOCK_ORDER_BOOK_ASKS,
MOCK_ORDER_BOOK_BIDS,
MOCK_ORDER_BOOK_LAST_PRICE,
MOCK_ORDER_BOOK_SPREAD,
} from '../api/mockData'
import { USE_MOCK_ORDER_BOOK } from '../config/mock'
const { t } = useI18n()
@ -118,48 +125,27 @@ const props = withDefaults(
// State
const activeTrade = ref('up')
// 使 props 退 mock
const internalAsks = ref<OrderBookRow[]>([
{ price: 45, shares: 1000.0 },
{ price: 44, shares: 2500.0 },
{ price: 43, shares: 1800.0 },
{ price: 42, shares: 3200.0 },
{ price: 41, shares: 2000.0 },
{ price: 40, shares: 1500.0 },
{ price: 39, shares: 800.0 },
{ price: 38, shares: 500.0 },
{ price: 37, shares: 300.0 },
])
const internalBids = ref<OrderBookRow[]>([
{ price: 36, shares: 200.0 },
{ price: 35, shares: 500.0 },
{ price: 34, shares: 1000.0 },
{ price: 33, shares: 1500.0 },
{ price: 32, shares: 2000.0 },
{ price: 31, shares: 2500.0 },
{ price: 30, shares: 3000.0 },
{ price: 29, shares: 2800.0 },
{ price: 28, shares: 2500.0 },
{ price: 27, shares: 2000.0 },
{ price: 26, shares: 1500.0 },
{ price: 25, shares: 1000.0 },
])
const internalLastPrice = ref(37)
const internalSpread = ref(1)
// 使 props 退 mock mockData
const internalAsks = ref<OrderBookRow[]>([...MOCK_ORDER_BOOK_ASKS])
const internalBids = ref<OrderBookRow[]>([...MOCK_ORDER_BOOK_BIDS])
const internalLastPrice = ref(MOCK_ORDER_BOOK_LAST_PRICE)
const internalSpread = ref(MOCK_ORDER_BOOK_SPREAD)
// 使 props mock
// 使 props USE_MOCK_ORDER_BOOK mock
const asks = computed(() =>
props.asks?.length ? props.asks : internalAsks.value,
props.asks?.length ? props.asks : USE_MOCK_ORDER_BOOK ? internalAsks.value : [],
)
const bids = computed(() =>
props.bids?.length ? props.bids : internalBids.value,
props.bids?.length ? props.bids : USE_MOCK_ORDER_BOOK ? internalBids.value : [],
)
const displayLastPrice = computed(() =>
props.lastPrice ?? internalLastPrice.value,
props.lastPrice ?? (USE_MOCK_ORDER_BOOK ? internalLastPrice.value : 0),
)
const displaySpread = computed(() =>
props.spread ?? (USE_MOCK_ORDER_BOOK ? internalSpread.value : 0),
)
const displaySpread = computed(() => props.spread ?? internalSpread.value)
// mock
// mock mock
let mockInterval: ReturnType<typeof setInterval> | undefined
watch(
() => props.connected || (props.asks?.length ?? 0) > 0,
@ -167,7 +153,7 @@ watch(
if (hasRealData && mockInterval) {
clearInterval(mockInterval)
mockInterval = undefined
} else if (!hasRealData && !mockInterval) {
} else if (!hasRealData && USE_MOCK_ORDER_BOOK && !mockInterval) {
mockInterval = setInterval(() => {
const randomAskIndex = Math.floor(Math.random() * internalAsks.value.length)
const askItem = internalAsks.value[randomAskIndex]

35
src/config/mock.ts Normal file
View File

@ -0,0 +1,35 @@
/**
*
* 便
*
* 使
* - .env VITE_USE_MOCK_DATA=true
* - VITE_USE_MOCK_CATEGORYVITE_USE_MOCK_EVENTVITE_USE_MOCK_ORDER_BOOKVITE_USE_MOCK_WALLET
*/
const env = typeof import.meta !== 'undefined' ? (import.meta as { env?: Record<string, string> }).env : {}
function isTruthy(val: string | undefined): boolean {
return val === 'true' || val === '1' || val === 'yes'
}
function isFalsy(val: string | undefined): boolean {
return val === 'false' || val === '0' || val === 'no'
}
const master = env?.VITE_USE_MOCK_DATA
/** 分类树Home 使用模拟分类(一层二层三层 UI 测试),默认 false */
export const USE_MOCK_CATEGORY =
isTruthy(master) || (master === undefined && isTruthy(env?.VITE_USE_MOCK_CATEGORY))
/** 事件/市场EventMarkets 接口失败时用 mock 兜底,默认 true */
export const USE_MOCK_EVENT =
isFalsy(master) ? false : isTruthy(master) || isTruthy(env?.VITE_USE_MOCK_EVENT) || env?.VITE_USE_MOCK_EVENT === undefined
/** 订单簿OrderBook 无 CLOB 数据时使用 mock默认 true */
export const USE_MOCK_ORDER_BOOK =
isFalsy(master) ? false : isTruthy(master) || isTruthy(env?.VITE_USE_MOCK_ORDER_BOOK) || env?.VITE_USE_MOCK_ORDER_BOOK === undefined
/** 钱包Wallet 持仓/订单/历史使用 mock默认 true */
export const USE_MOCK_WALLET =
isFalsy(master) ? false : isTruthy(master) || isTruthy(env?.VITE_USE_MOCK_WALLET) || env?.VITE_USE_MOCK_WALLET === undefined

View File

@ -197,7 +197,8 @@ import {
type PmEventListItem,
type PmEventMarketItem,
} from '../api/event'
import { MOCK_EVENT_LIST } from '../api/mockEventList'
import { getMockEventById } from '../api/mockData'
import { USE_MOCK_EVENT } from '../config/mock'
import { useI18n } from 'vue-i18n'
import { useUserStore } from '../stores/user'
import { useToastStore } from '../stores/toast'
@ -643,7 +644,7 @@ async function loadEventDetail() {
eventDetail.value = res.data ?? null
detailError.value = null
} else {
const fallback = isNumericId ? getMockEventById(numId) : null
const fallback = USE_MOCK_EVENT && isNumericId ? getMockEventById(numId) : null
if (fallback) {
eventDetail.value = fallback
detailError.value = null
@ -653,7 +654,7 @@ async function loadEventDetail() {
}
}
} catch (e) {
const fallback = isNumericId ? getMockEventById(numId) : null
const fallback = USE_MOCK_EVENT && isNumericId ? getMockEventById(numId) : null
if (fallback) {
eventDetail.value = fallback
detailError.value = null
@ -666,11 +667,6 @@ async function loadEventDetail() {
}
}
function getMockEventById(id: number): PmEventListItem | null {
const item = MOCK_EVENT_LIST.find((e) => e.ID === id)
return item && (item.markets?.length ?? 0) > 1 ? item : null
}
onMounted(() => {
loadEventDetail()
window.addEventListener('resize', handleResize)

View File

@ -322,6 +322,7 @@ import {
resolveCategoryIconColor,
type CategoryTreeNode,
} from '../api/category'
import { USE_MOCK_CATEGORY } from '../config/mock'
import { useI18n } from 'vue-i18n'
import { useSearchHistory } from '../composables/useSearchHistory'
import { useToastStore } from '../stores/toast'
@ -651,8 +652,6 @@ onMounted(() => {
}
}
/** 开发时设为 true 可始终使用模拟数据查看一二三层 UI */
const USE_MOCK_CATEGORY = false
if (USE_MOCK_CATEGORY) {
categoryTree.value = enrichWithIcons(MOCK_CATEGORY_TREE)
initCategorySelection()

View File

@ -573,6 +573,13 @@ import DepositDialog from '../components/DepositDialog.vue'
import WithdrawDialog from '../components/WithdrawDialog.vue'
import { useUserStore } from '../stores/user'
import { pmCancelOrder } from '../api/market'
import {
MOCK_TOKEN_ID,
MOCK_WALLET_POSITIONS,
MOCK_WALLET_ORDERS,
MOCK_WALLET_HISTORY,
} from '../api/mockData'
import { USE_MOCK_WALLET } from '../config/mock'
const { mobile } = useDisplay()
const userStore = useUserStore()
@ -669,156 +676,15 @@ interface HistoryItem {
iconClass?: string
}
const positions = ref<Position[]>([
{
id: 'p1',
market: 'Bitcoin Up or Down - February 9, 2:00AM-2:15AM ET',
iconChar: '₿',
iconClass: 'position-icon-btc',
outcomeTag: 'Down 72¢',
outcomePillClass: 'pill-down',
shares: '6.9 shares',
avgNow: '72¢ → 0.5¢',
bet: '$4.95',
toWin: '$6.87',
value: '$0.03',
valueChange: '-$4.91',
valueChangePct: '99.31%',
valueChangeLoss: true,
sellOutcome: 'Down',
outcomeWord: 'Down',
},
{
id: 'p2',
market: 'Bitcoin Up or Down - February 9, 2:15AM-2:30AM ET',
iconChar: '₿',
iconClass: 'position-icon-btc',
outcomeTag: 'Up 26¢',
outcomePillClass: 'pill-yes',
shares: '3.8 shares',
avgNow: '28¢ → 26¢',
bet: '$0.99',
toWin: '$3.54',
value: '$0.90',
valueChange: '-$0.09',
valueChangePct: '8.9%',
valueChangeLoss: true,
sellOutcome: 'Up',
outcomeWord: 'Up',
},
{
id: 'p3',
market: 'Will ETH merge complete by Q3?',
iconChar: 'Ξ',
iconClass: 'position-icon-eth',
outcomeTag: 'Yes 48¢',
outcomePillClass: 'pill-yes',
shares: '30 shares',
avgNow: '45¢ → 48¢',
bet: '$30',
toWin: '$36',
value: '$32',
valueChange: '+$2',
valueChangePct: '6.67%',
valueChangeLoss: false,
sellOutcome: 'Yes',
outcomeWord: 'Yes',
},
])
const MOCK_TOKEN_ID =
'59966088656508531737144108943848781534186324373509174641856486864137458635937'
const openOrders = ref<OpenOrder[]>([
{
id: 'o1',
market: 'Bitcoin Up or Down - February 9, 2:45AM-3:00AM ET',
side: 'Yes',
outcome: 'Up',
price: '1¢',
filled: '0',
total: '$0.05',
expiration: 'Until Cancelled',
actionLabel: 'Buy Up',
filledDisplay: '0/5',
iconChar: '₿',
iconClass: 'position-icon-btc',
orderID: 5,
tokenID: MOCK_TOKEN_ID,
},
{
id: 'o2',
market: 'Will Bitcoin hit $100k by end of 2025?',
side: 'Yes',
outcome: 'Yes',
price: '70¢',
filled: '0',
total: '$70',
expiration: 'Dec 31, 2025',
orderID: 5,
tokenID: MOCK_TOKEN_ID,
},
{
id: 'o3',
market: 'Will ETH merge complete by Q3?',
side: 'No',
outcome: 'No',
price: '52¢',
filled: '25',
total: '$26',
expiration: 'Sep 30, 2025',
orderID: 5,
tokenID: MOCK_TOKEN_ID,
},
])
const history = ref<HistoryItem[]>([
{
id: 'h1',
market: 'Bitcoin Up or Down - February 9, 3:00AM-3:15AM ET',
side: 'No',
activity: 'Sell No',
activityDetail: 'Sold 1 Down at 50¢',
value: '$0.50',
profitLoss: '+$0.50',
profitLossNegative: false,
timeAgo: '3 minutes ago',
avgPrice: '50¢',
shares: '1',
iconChar: '₿',
iconClass: 'position-icon-btc',
},
{
id: 'h2',
market: 'Bitcoin Up or Down - February 9, 3:00AM-3:15AM ET',
side: 'Yes',
activity: 'Sell Yes',
activityDetail: 'Sold 1 Up at 63¢',
value: '$0.63',
profitLoss: '+$0.63',
profitLossNegative: false,
timeAgo: '6 minutes ago',
iconChar: '₿',
iconClass: 'position-icon-btc',
},
{
id: 'h3',
market: 'Bitcoin Up or Down - February 9, 3:00AM-3:15AM ET',
side: 'Yes',
activity: 'Split',
activityDetail: 'Split',
value: '-$1.00',
profitLoss: '-$1.00',
profitLossNegative: true,
timeAgo: '7 minutes ago',
iconChar: '₿',
iconClass: 'position-icon-btc',
},
{
id: 'h4',
market: 'Will ETH merge complete by Q3?',
side: 'No',
activity: 'Sell No',
value: '$35.20',
},
])
const positions = ref<Position[]>(
USE_MOCK_WALLET ? [...MOCK_WALLET_POSITIONS] : [],
)
const openOrders = ref<OpenOrder[]>(
USE_MOCK_WALLET ? [...MOCK_WALLET_ORDERS] : [],
)
const history = ref<HistoryItem[]>(
USE_MOCK_WALLET ? [...MOCK_WALLET_HISTORY] : [],
)
function matchSearch(text: string): boolean {
const q = search.value.trim().toLowerCase()