新增:充提历史页

This commit is contained in:
马丁 2026-05-03 00:34:13 +08:00
parent 69c4223af1
commit 98508a7814
9 changed files with 198 additions and 33 deletions

View File

@ -77,6 +77,7 @@ export interface GetHistoryRecordListClientParams {
name?: string
bio?: string
createdAtRange?: string[]
isFunding?: boolean
}
/** 响应 data 可能为分页或数组 */
@ -111,6 +112,7 @@ export async function getHistoryRecordListClient(
name: params.name,
bio: params.bio,
createdAtRange: params.createdAtRange,
isFunding: params.isFunding === undefined ? undefined : String(params.isFunding),
})
return get<HistoryRecordListClientResponse>('/hr/getHistoryRecordListClient', query, config)
}

View File

@ -72,7 +72,7 @@
:disabled="!canSubmit"
@click="submitWithdraw"
>
{{ t('withdraw.title') }}
{{ t('withdraw.applyWithdraw') }}
</v-btn>
</v-card-text>
</v-card>

View File

@ -255,7 +255,8 @@
"expirationLabel": "Expiration:",
"youWon": "You won ${amount}",
"claim": "Claim",
"withdrawals": "Withdrawals",
"withdrawals": "Withdrawal History",
"applyWithdrawHistory": "Apply Withdrawal History",
"withdrawStatusAll": "All",
"withdrawStatusPending": "Under review",
"withdrawStatusSuccess": "Withdrawn",
@ -298,7 +299,7 @@
"edit": "Edit",
"walletOverview": "Wallet Overview",
"walletDetail": "Wallet details",
"walletSub": "Available ${available} Frozen ${frozen}",
"walletSub": "Available ${available} Frozen ${frozen} Free ${freeMoney}",
"accountSettings": "Account & Settings",
"walletManage": "Wallet Management",
"apiKeyManage": "API KEY Management",
@ -406,10 +407,13 @@
"userRejected": "You cancelled the wallet request",
"insufficientUsdcBalance": "Not enough USDC on this network for this amount. On Polygon, native USDC and USDC.e are different tokens—use the one you actually hold, or bridge/swap first.",
"txConfirmTimeout": "Transaction was submitted but not confirmed in time. Check it in your wallet or a block explorer.",
"walletRpcIncomplete": "Your wallet returned incomplete transaction data. If issues persist, update MetaMask or change the RPC."
"walletRpcIncomplete": "Your wallet returned incomplete transaction data. If issues persist, update MetaMask or change the RPC.",
"depositHistory": "Deposit History",
"depositStatusAll": "All"
},
"withdraw": {
"title": "Withdraw",
"applyWithdraw": "Apply for withdrawal",
"polymarketBalance": "Balance:",
"amountUsd": "Amount (USD)",
"max": "Max",
@ -433,11 +437,11 @@
"walletMismatch": "Switch your browser wallet to the same account you used to sign in."
},
"earnActivity": {
"title": "Earn Liquidity",
"title": "Participate to Earn",
"subtitle": "Participate to earn extra returns",
"tiersTitle": "Activity Tiers",
"myLockInfo": "My Lock Info",
"lockedAmount": "Locked Amount",
"myLockInfo": "My Participation",
"lockedAmount": "Current Locked Amount",
"freeAmount": "Free Amount",
"unlockDate": "Unlock Date",
"tierLevel": "Tier {n}",

View File

@ -256,6 +256,7 @@
"youWon": "獲得 $${amount}",
"claim": "受け取る",
"withdrawals": "出金履歴",
"applyWithdrawHistory": "出金申請履歴",
"withdrawStatusAll": "すべて",
"withdrawStatusPending": "審査中",
"withdrawStatusSuccess": "出金成功",
@ -298,7 +299,7 @@
"edit": "編集",
"walletOverview": "ウォレット概要",
"walletDetail": "ウォレット詳細",
"walletSub": "利用可能残高 ${available} 凍結 ${frozen}",
"walletSub": "利用可能残高 ${available} 凍結 ${frozen} 出金可能額 ${freeMoney}",
"accountSettings": "アカウントと設定",
"walletManage": "ウォレット管理",
"apiKeyManage": "API KEY 管理",
@ -406,10 +407,13 @@
"userRejected": "ウォレットの操作をキャンセルしました",
"insufficientUsdcBalance": "このネットワーク上の USDC 残高が不足しています。Polygon ではネイティブ USDC と USDC.e は別トークンです。保有している方で送るか、ブリッジ・スワップ後に再試行してください。",
"txConfirmTimeout": "トランザクションは送信されましたが、一定時間内に確認されませんでした。ウォレットまたはブロックエクスプローラーでご確認ください。",
"walletRpcIncomplete": "ウォレットから返ったトランザクション情報が不完全です。MetaMask の更新や RPC の変更をお試しください。"
"walletRpcIncomplete": "ウォレットから返ったトランザクション情報が不完全です。MetaMask の更新や RPC の変更をお試しください。",
"depositHistory": "入金履歴",
"depositStatusAll": "すべて"
},
"withdraw": {
"title": "出金",
"applyWithdraw": "出金申請",
"polymarketBalance": "残高:",
"amountUsd": "金額 (USD)",
"max": "最大",
@ -433,11 +437,11 @@
"walletMismatch": "ログイン時に使用したアカウントにブラウザのウォレットを切り替えてください。"
},
"earnActivity": {
"title": "流動性を稼いでロック",
"title": "キャンペーンに参加して稼ぐ",
"subtitle": "キャンペーンに参加して追加收益を獲得",
"tiersTitle": "キャンペーンティア",
"myLockInfo": "マイロック情報",
"lockedAmount": "ロック合計額",
"myLockInfo": "マイ参加状況",
"lockedAmount": "現在のロック金額",
"freeAmount": "出金可能額",
"unlockDate": "ロック解除日時",
"tierLevel": "第 {n} ティア",

View File

@ -256,6 +256,7 @@
"youWon": "당첨 $${amount}",
"claim": "수령",
"withdrawals": "출금 내역",
"applyWithdrawHistory": "출금 신청 내역",
"withdrawStatusAll": "전체",
"withdrawStatusPending": "검토 중",
"withdrawStatusSuccess": "출금 완료",
@ -298,7 +299,7 @@
"edit": "편집",
"walletOverview": "지갑 개요",
"walletDetail": "지갑 상세",
"walletSub": "사용 가능 잔액 ${available} 동결 ${frozen}",
"walletSub": "사용 가능 잔액 ${available} 동결 ${frozen} 출금 가능 금액 ${freeMoney}",
"accountSettings": "계정 및 설정",
"walletManage": "지갑 관리",
"apiKeyManage": "API KEY 관리",
@ -406,10 +407,13 @@
"userRejected": "지갑에서 작업을 취소했습니다",
"insufficientUsdcBalance": "이 네트워크의 USDC 잔액이 부족합니다. Polygon에서는 네이티브 USDC와 USDC.e가 다른 토큰입니다. 보유 중인 종류로 보내거나 브릿지/스왑 후 다시 시도하세요.",
"txConfirmTimeout": "거래는 제출되었지만 제한 시간 안에 확인되지 않았습니다. 지갑이나 블록 탐색기에서 확인해 주세요.",
"walletRpcIncomplete": "지갑에서 반환된 거래 데이터가 불완전합니다. MetaMask를 업데이트하거나 RPC를 변경해 보세요."
"walletRpcIncomplete": "지갑에서 반환된 거래 데이터가 불완전합니다. MetaMask를 업데이트하거나 RPC를 변경해 보세요.",
"depositHistory": "입금 내역",
"depositStatusAll": "전체"
},
"withdraw": {
"title": "출금",
"applyWithdraw": "출금 신청",
"polymarketBalance": "잔액:",
"amountUsd": "금액 (USD)",
"max": "최대",
@ -433,11 +437,11 @@
"walletMismatch": "로그인에 사용한 계정과 동일한 계정으로 브라우저 지갑을 전환해 주세요."
},
"earnActivity": {
"title": "유동성 획득 잠금",
"title": "이벤트 참여하여 돈 벌기",
"subtitle": "이벤트에 참여하여 추가 수익 획득",
"tiersTitle": "이벤트 티어",
"myLockInfo": "내 잠금 정보",
"lockedAmount": "전체 잠금 금액",
"myLockInfo": "내 참여 정보",
"lockedAmount": "현재 참여 잠금 금액",
"freeAmount": "출금 가능 금액",
"unlockDate": "잠금 해제 시간",
"tierLevel": "티어 {n}",

View File

@ -256,6 +256,7 @@
"youWon": "您赢得 ${amount}",
"claim": "领取",
"withdrawals": "提现记录",
"applyWithdrawHistory": "申请提现记录",
"withdrawStatusAll": "全部",
"withdrawStatusPending": "审核中",
"withdrawStatusSuccess": "提现成功",
@ -298,7 +299,7 @@
"edit": "编辑",
"walletOverview": "钱包总览",
"walletDetail": "钱包详情",
"walletSub": "可用余额 ${available} 冻结 ${frozen}",
"walletSub": "可用余额 ${available} 冻结 ${frozen} 可提现金额 ${freeMoney}",
"accountSettings": "账户与设置",
"walletManage": "钱包管理",
"apiKeyManage": "API KEY 管理",
@ -406,10 +407,13 @@
"userRejected": "您已取消钱包中的操作",
"insufficientUsdcBalance": "当前网络上的 USDC 余额不足。若在 Polygon请确认您持有的是「原生 USDC」或「USDC.e」或先兑换/跨链后再试。",
"txConfirmTimeout": "交易已提交,但长时间未在链上确认,请在浏览器钱包或区块浏览器中查看该笔交易。",
"walletRpcIncomplete": "钱包返回的交易数据不完整。已改为直连接口发交易;若仍失败请更新 MetaMask 或更换 RPC。"
"walletRpcIncomplete": "钱包返回的交易数据不完整。已改为直连接口发交易;若仍失败请更新 MetaMask 或更换 RPC。",
"depositHistory": "充值历史",
"depositStatusAll": "全部"
},
"withdraw": {
"title": "提现",
"applyWithdraw": "申请提现",
"polymarketBalance": "余额:",
"amountUsd": "金额 (USD)",
"max": "最大",
@ -425,6 +429,7 @@
"insufficientBalance": "余额不足",
"close": "关闭",
"withdrawals": "提现记录",
"applyWithdrawHistory": "申请提现记录",
"withdrawStatusAll": "全部",
"withdrawStatusPending": "审核中",
"withdrawStatusSuccess": "提现成功",
@ -445,11 +450,11 @@
"walletMismatch": "请在浏览器钱包中切换到您登录时使用的账户。"
},
"earnActivity": {
"title": "锁仓赚取流动性",
"title": "参与活动赚钱",
"subtitle": "参与活动获得额外收益",
"tiersTitle": "活动档位",
"myLockInfo": "我的锁仓情况",
"lockedAmount": "当前流动性锁仓金额",
"myLockInfo": "我的参与情况",
"lockedAmount": "当前参与锁仓金额",
"freeAmount": "可提现金额",
"unlockDate": "解锁时间",
"tierLevel": "第 {n} 档",

View File

@ -204,8 +204,8 @@
"weeksAgo": "{n}週前"
},
"wallet": {
"availableAssets": "可用資產",
"portfolio": "資產組合",
"availableAssets": "可用資產",
"portfolio": "資產組合",
"today": "今日",
"deposit": "入金",
"withdraw": "提現",
@ -256,6 +256,7 @@
"youWon": "您贏得 ${amount}",
"claim": "領取",
"withdrawals": "提現記錄",
"applyWithdrawHistory": "申請提現記錄",
"withdrawStatusAll": "全部",
"withdrawStatusPending": "審核中",
"withdrawStatusSuccess": "提現成功",
@ -298,7 +299,7 @@
"edit": "編輯",
"walletOverview": "錢包總覽",
"walletDetail": "錢包詳情",
"walletSub": "可用餘額 ${available} 凍結 ${frozen}",
"walletSub": "可用餘額 ${available} 凍結 ${frozen} 可提現金額 ${freeMoney}",
"accountSettings": "帳戶與設定",
"walletManage": "錢包管理",
"apiKeyManage": "API KEY 管理",
@ -406,10 +407,13 @@
"userRejected": "您已取消錢包中的操作",
"insufficientUsdcBalance": "目前網路上的 USDC 餘額不足。若在 Polygon請確認持有的是「原生 USDC」或「USDC.e」或先兌換/跨鏈後再試。",
"txConfirmTimeout": "交易已提交,但長時間未在鏈上確認,請在瀏覽器錢包或區塊瀏覽器中查看該筆交易。",
"walletRpcIncomplete": "錢包回傳的交易資料不完整。已改為直接介面發送;若仍失敗請更新 MetaMask 或更換 RPC。"
"walletRpcIncomplete": "錢包回傳的交易資料不完整。已改為直接介面發送;若仍失敗請更新 MetaMask 或更換 RPC。",
"depositHistory": "充值歷史",
"depositStatusAll": "全部"
},
"withdraw": {
"title": "提現",
"applyWithdraw": "申請提現",
"polymarketBalance": "餘額:",
"amountUsd": "金額 (USD)",
"max": "最大",
@ -433,11 +437,11 @@
"walletMismatch": "請在瀏覽器錢包中切換至您登入時使用的帳戶。"
},
"earnActivity": {
"title": "鎖倉賺取流動性",
"title": "參與活動賺錢",
"subtitle": "參與活動獲得額外收益",
"tiersTitle": "活動檔位",
"myLockInfo": "我的鎖倉情況",
"lockedAmount": "當前流動性鎖倉金額",
"myLockInfo": "我的參與情況",
"lockedAmount": "當前參與鎖倉金額",
"freeAmount": "可提現金額",
"unlockDate": "解鎖時間",
"tierLevel": "第 {n} 檔",

View File

@ -50,7 +50,7 @@
${{ totalBalance }}
</div>
<div class="wallet-sub">
{{ t('profile.walletSub', { available: availableBalance, frozen: frozenBalance }) }}
{{ t('profile.walletSub', { available: availableBalance, frozen: frozenBalance, freeMoney: freeMoney }) }}
</div>
<div class="wallet-actions">
<button type="button" class="wallet-action-primary" @click="goWallet">
@ -178,6 +178,7 @@ import { useLocaleStore } from '../stores/locale'
import { useToastStore } from '../stores/toast'
import { useUserStore, type UserInfo } from '../stores/user'
import { setSelfUsername, setSelfHeaderImg } from '@/api/user'
import { getLockMoney } from '@/api/earnActivity'
import { upload } from '@/api/fileUpload'
import type { LocaleCode } from '@/plugins/i18n'
@ -239,6 +240,13 @@ const walletAddressShort = computed(() => {
return `${value.slice(0, 6)}...${value.slice(-4)}`
})
const formatAmount = (val: number | string | undefined | null) => {
if (val == null) return '0.00'
const num = typeof val === 'string' ? parseFloat(val) : val
if (!Number.isFinite(num)) return '0.00'
return Math.floor(num / 1000000).toLocaleString()
}
const rawUser = computed(() => (userStore.user ?? {}) as Record<string, unknown>)
const userNameRaw = computed(() => {
const v = rawUser.value.userName
@ -275,6 +283,27 @@ const availableBalance = computed(() => {
const frozenBalance = computed(() => {
return readStringFromUser(['frozenBalance', 'frozen', 'walletFrozen']) || '0.00'
})
const freeMoney = ref('0.00')
async function fetchLockInfo() {
if (!userStore.isLoggedIn) return
const headers = userStore.getAuthHeaders()
if (!headers) return
try {
const res = await getLockMoney({ headers })
if (res.code === 0 && res.data) {
freeMoney.value = formatAmount(res.data.freeMoney)
}
} catch (error) {
console.error('Failed to fetch lock info:', error)
}
}
onMounted(() => {
fetchLockInfo()
})
const settingItems = computed<SettingItem[]>(() => [
{ label: t('profile.walletManage'), action: 'wallet' },
{ label: t('profile.apiKeyManage'), route: '/api-key' },

View File

@ -62,6 +62,7 @@
<v-tab value="positions">{{ t('wallet.positions') }}</v-tab>
<v-tab value="orders">{{ t('wallet.openOrders') }}</v-tab>
<v-tab value="history">{{ t('wallet.history') }}</v-tab>
<v-tab value="depositHistory">{{ t('deposit.depositHistory') }}</v-tab>
<v-tab value="withdrawals">{{ t('wallet.withdrawals') }}</v-tab>
</v-tabs>
<v-card class="table-card wallet-design-card" elevation="0" rounded="lg">
@ -322,6 +323,55 @@
</div>
</div>
</template>
<template v-else-if="activeTab === 'depositHistory'">
<div class="history-mobile-list">
<div v-if="depositHistoryLoading" class="empty-cell empty-cell--loading">
<v-progress-circular indeterminate size="36" width="2" />
<span>{{ t('common.loading') }}</span>
</div>
<div v-else-if="filteredDepositHistory.length === 0" class="empty-cell">
{{ t('common.noData') }}
</div>
<div
v-for="h in paginatedDepositHistory"
:key="h.id"
class="history-mobile-card design-history-card"
:class="[
{ 'wallet-row--clickable': true },
{ 'wallet-row--nav': historyRowCanOpenDetail(h) },
]"
:role="historyRowCanOpenDetail(h) ? 'button' : undefined"
:tabindex="historyRowCanOpenDetail(h) ? 0 : undefined"
@click="onHistoryRowClick(h)"
@keydown.enter.prevent="onHistoryRowClick(h)"
@keydown.space.prevent="onHistoryRowClick(h)"
>
<div class="design-funding-left">
<div class="history-mobile-icon funding-icon-shell">
<div class="funding-icon-disc">
<v-icon size="20" class="funding-icon-usd">mdi-currency-usd</v-icon>
</div>
</div>
<div class="history-mobile-main">
<MarqueeTitle
:text="getFundingTitle(h)"
title-class="history-mobile-title"
fast
/>
<div class="history-mobile-activity">{{ h.timeAgo || '—' }}</div>
</div>
</div>
<span
:class="[
'history-mobile-pl',
isWithdrawalHistory(h) || h.profitLossNegative ? 'pl-loss' : 'pl-gain',
]"
>
{{ h.profitLoss ?? h.value }}
</span>
</div>
</div>
</template>
<template v-else-if="activeTab === 'withdrawals'">
<div class="withdrawals-mobile-list">
<div v-if="withdrawalsLoading" class="empty-cell empty-cell--loading">
@ -601,7 +651,7 @@ const plTimeRanges = computed(() => [
{ label: t('wallet.pl1M'), value: '1M' },
{ label: t('wallet.plAll'), value: 'ALL' },
])
const activeTab = ref<'positions' | 'orders' | 'history' | 'withdrawals'>('positions')
const activeTab = ref<'positions' | 'orders' | 'history' | 'depositHistory' | 'withdrawals'>('positions')
const search = ref('')
const withdrawStatusFilter = ref<string>('')
const withdrawStatusOptions = computed(() => [
@ -1026,6 +1076,10 @@ const historyList = ref<HistoryItem[]>([])
const historyTotal = ref(0)
const historyLoading = ref(false)
const depositHistoryList = ref<HistoryItem[]>([])
const depositHistoryTotal = ref(0)
const depositHistoryLoading = ref(false)
/** 历史记录来自 GET /hr/getHistoryRecordListClient需鉴权按当前用户分页 */
async function loadHistoryOrders() {
if (USE_MOCK_WALLET) return
@ -1049,6 +1103,7 @@ async function loadHistoryOrders() {
page: page.value,
pageSize: itemsPerPage.value,
userId: userID,
isFunding: false,
},
{ headers },
)
@ -1068,6 +1123,48 @@ async function loadHistoryOrders() {
}
}
async function loadDepositHistoryOrders() {
if (USE_MOCK_WALLET) return
const headers = userStore.getAuthHeaders()
if (!headers) {
depositHistoryList.value = []
depositHistoryTotal.value = 0
return
}
const uid = userStore.user?.id ?? userStore.user?.ID
const userID = uid != null ? Number(uid) : undefined
if (!userID || !Number.isFinite(userID)) {
depositHistoryList.value = []
depositHistoryTotal.value = 0
return
}
depositHistoryLoading.value = true
try {
const res = await getHistoryRecordListClient(
{
page: page.value,
pageSize: itemsPerPage.value,
userId: userID,
isFunding: true,
},
{ headers },
)
if (res.code === 0 || res.code === 200) {
const { list, total } = getHistoryRecordList(res.data)
depositHistoryList.value = list
depositHistoryTotal.value = total
} else {
depositHistoryList.value = []
depositHistoryTotal.value = 0
}
} catch {
depositHistoryList.value = []
depositHistoryTotal.value = 0
} finally {
depositHistoryLoading.value = false
}
}
async function loadWithdrawals() {
const headers = userStore.getAuthHeaders()
if (!headers) {
@ -1135,7 +1232,7 @@ function getWithdrawTokenSymbol(w: SettlementRequestClientItem): string {
const chain = (w.chain ?? '').toLowerCase()
if (chain.includes('btc') || chain.includes('bitcoin')) return 'BTC'
if (chain.includes('eth') || chain.includes('ethereum')) return 'ETH'
return 'USDT'
return 'USDC'
}
function getWithdrawAmountText(w: SettlementRequestClientItem): string {
@ -1208,7 +1305,11 @@ const filteredOpenOrders = computed(() => {
})
const filteredHistory = computed(() => {
const list = USE_MOCK_WALLET ? history.value : historyList.value
return list.filter((h) => matchSearch(h.market))
return list.filter((h) => matchSearch(h.market) && (USE_MOCK_WALLET ? !isFundingHistory(h) : true))
})
const filteredDepositHistory = computed(() => {
const list = USE_MOCK_WALLET ? history.value : depositHistoryList.value
return list.filter((h) => matchSearch(h.market) && (USE_MOCK_WALLET ? isFundingHistory(h) : true))
})
const page = ref(1)
@ -1231,6 +1332,10 @@ const paginatedHistory = computed(() => {
if (USE_MOCK_WALLET) return paginate(filteredHistory.value)
return filteredHistory.value
})
const paginatedDepositHistory = computed(() => {
if (USE_MOCK_WALLET) return paginate(filteredDepositHistory.value)
return filteredDepositHistory.value
})
const totalPagesPositions = computed(() => {
const total = USE_MOCK_WALLET ? filteredPositions.value.length : positionTotal.value
@ -1244,6 +1349,10 @@ const totalPagesHistory = computed(() => {
const total = USE_MOCK_WALLET ? filteredHistory.value.length : historyTotal.value
return Math.max(1, Math.ceil(total / itemsPerPage.value))
})
const totalPagesDepositHistory = computed(() => {
const total = USE_MOCK_WALLET ? filteredDepositHistory.value.length : depositHistoryTotal.value
return Math.max(1, Math.ceil(total / itemsPerPage.value))
})
const totalPagesWithdrawals = computed(() =>
Math.max(1, Math.ceil(withdrawalsTotal.value / itemsPerPage.value)),
)
@ -1254,12 +1363,14 @@ const currentListTotal = computed(() => {
if (activeTab.value === 'orders')
return USE_MOCK_WALLET ? filteredOpenOrders.value.length : openOrderTotal.value
if (activeTab.value === 'withdrawals') return withdrawalsTotal.value
if (activeTab.value === 'depositHistory') return USE_MOCK_WALLET ? filteredDepositHistory.value.length : depositHistoryTotal.value
return USE_MOCK_WALLET ? filteredHistory.value.length : historyTotal.value
})
const currentTotalPages = computed(() => {
if (activeTab.value === 'positions') return totalPagesPositions.value
if (activeTab.value === 'orders') return totalPagesOrders.value
if (activeTab.value === 'withdrawals') return totalPagesWithdrawals.value
if (activeTab.value === 'depositHistory') return totalPagesDepositHistory.value
return totalPagesHistory.value
})
const currentPageStart = computed(() =>
@ -1274,12 +1385,14 @@ watch(activeTab, (tab) => {
if (tab === 'positions' && !USE_MOCK_WALLET) loadPositionList()
if (tab === 'orders' && !USE_MOCK_WALLET) loadOpenOrders()
if (tab === 'history' && !USE_MOCK_WALLET) loadHistoryOrders()
if (tab === 'depositHistory' && !USE_MOCK_WALLET) loadDepositHistoryOrders()
if (tab === 'withdrawals') loadWithdrawals()
})
watch([page, itemsPerPage], () => {
if (activeTab.value === 'positions' && !USE_MOCK_WALLET) loadPositionList()
if (activeTab.value === 'orders' && !USE_MOCK_WALLET) loadOpenOrders()
if (activeTab.value === 'history' && !USE_MOCK_WALLET) loadHistoryOrders()
if (activeTab.value === 'depositHistory' && !USE_MOCK_WALLET) loadDepositHistoryOrders()
if (activeTab.value === 'withdrawals') loadWithdrawals()
})
watch(withdrawStatusFilter, () => {