增加:组合资产和可用资产

This commit is contained in:
马丁 2026-07-07 22:35:36 +08:00
parent c088670028
commit 2bfd171e11
8 changed files with 79 additions and 10 deletions

View File

@ -192,7 +192,16 @@ async function onMenuClick(id: string) {
</template>
<template v-else>
<v-btn class="balance-btn" variant="text" min-width="auto" padding="4 12" @click="$router.push('/wallet')">
<span class="balance-text">${{ userStore.totalAssetValue }}</span>
<div class="balance-group">
<div class="balance-item">
<span class="balance-label">{{ t('wallet.portfolio') }}</span>
<span class="balance-value">${{ userStore.totalAssetValue }}</span>
</div>
<div class="balance-item">
<span class="balance-label">{{ t('wallet.cash') }}</span>
<span class="balance-value">${{ userStore.availableAssetValue }}</span>
</div>
</div>
</v-btn>
<v-btn icon variant="text" class="avatar-btn" :aria-label="t('common.user')"
@click="$router.push('/profile')">
@ -399,9 +408,31 @@ async function onMenuClick(id: string) {
text-transform: none;
}
.balance-text {
.balance-group {
display: flex;
align-items: stretch;
gap: 16px;
white-space: nowrap;
line-height: 1.1;
}
.balance-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 2px;
}
.balance-label {
font-size: 0.7rem;
color: rgba(0, 0, 0, 0.5);
font-weight: 500;
font-size: 0.95rem;
}
.balance-value {
font-size: 1rem;
font-weight: 700;
color: #3a9b5d;
}
.back-btn {
@ -435,6 +466,18 @@ async function onMenuClick(id: string) {
.brand-name {
font-size: 0.96rem;
}
.balance-group {
gap: 12px;
}
.balance-label {
font-size: 0.64rem;
}
.balance-value {
font-size: 0.9rem;
}
}
/* 底部导航整条栏上方淡投影z-index 确保覆盖滚动条,显示在滚动条上层 */

View File

@ -235,6 +235,7 @@
"wallet": {
"availableAssets": "Available Assets",
"portfolio": "Portfolio",
"cash": "Cash",
"today": "Today",
"deposit": "Deposit",
"withdraw": "Withdraw",

View File

@ -235,6 +235,7 @@
"wallet": {
"availableAssets": "利用可能資産",
"portfolio": "ポートフォリオ",
"cash": "現金",
"today": "今日",
"deposit": "入金",
"withdraw": "出金",

View File

@ -235,6 +235,7 @@
"wallet": {
"availableAssets": "사용 가능 자산",
"portfolio": "포트폴리오",
"cash": "현금",
"today": "오늘",
"deposit": "입금",
"withdraw": "출금",

View File

@ -235,6 +235,7 @@
"wallet": {
"availableAssets": "可用资产",
"portfolio": "资产组合",
"cash": "现金",
"today": "今日",
"deposit": "入金",
"withdraw": "提现",

View File

@ -235,6 +235,7 @@
"wallet": {
"availableAssets": "可用資產",
"portfolio": "資產組合",
"cash": "現金",
"today": "今日",
"deposit": "入金",
"withdraw": "提現",

View File

@ -21,8 +21,8 @@ app.use(router)
setHttpUnauthorizedHandler(() => {
const userStore = useUserStore(pinia)
userStore.clearLocalSession()
if (router.currentRoute.value.name !== 'login') {
router.replace({ name: 'login' })
if (router.currentRoute.value.name !== 'home') {
router.replace({ name: 'home' })
}
})

View File

@ -85,12 +85,19 @@ export const useUserStore = defineStore('user', () => {
/** 钱包余额显示,如 "0.00",可从接口或 UserSocket 推送更新 */
const balance = ref<string>('0.00')
/** 锁定余额显示,如 "0.00",可从接口或 UserSocket 推送更新 */
const lockedBalance = ref<string>('0.00')
const positionsValue = ref<number>(0)
/** 总资产:余额 + 仓位当前价值 */
/** 可用资产:仅可用余额 */
const availableAssetValue = computed(() => balance.value)
/** 组合资产:可用 + 锁定 + 持仓价值 */
const totalAssetValue = computed(() => {
const bal = parseFloat(balance.value) || 0
return (bal + positionsValue.value).toFixed(2)
const locked = parseFloat(lockedBalance.value) || 0
return (bal + locked + positionsValue.value).toFixed(2)
})
let userSdkRef: UserSdk | null = null
@ -117,6 +124,10 @@ export const useUserStore = defineStore('user', () => {
if (avail != null) {
balance.value = formatUsdcBalance(String(avail))
}
const locked = (data as BalanceData & { locked?: string }).locked ?? data.frozen
if (locked != null) {
lockedBalance.value = formatUsdcBalance(String(locked))
}
})
sdk.onPositionUpdate((data) => {
positionUpdateCallbacks.forEach((cb) => cb(data as PositionData & Record<string, unknown>))
@ -205,8 +216,13 @@ export const useUserStore = defineStore('user', () => {
try {
const res = await getUsdcBalance(headers)
if (res.code === 0 && res.data) {
if (res.data.available != null) {
balance.value = formatUsdcBalance(res.data.available)
}
if (res.data.locked != null) {
lockedBalance.value = formatUsdcBalance(res.data.locked)
}
}
} catch (e) {
console.error('[fetchUsdcBalance] 请求失败:', e)
}
@ -220,11 +236,14 @@ export const useUserStore = defineStore('user', () => {
const res = await getUserInfo(headers)
const data = res.data as Record<string, unknown> | undefined
if (res.code !== 0 && res.code !== 200) return
// 更新余额data.balance.available
const bal = data?.balance as { available?: string } | undefined
// 更新余额data.balance.available / data.balance.locked
const bal = data?.balance as { available?: string; locked?: string } | undefined
if (bal?.available != null) {
balance.value = formatUsdcBalance(String(bal.available))
}
if (bal?.locked != null) {
lockedBalance.value = formatUsdcBalance(String(bal.locked))
}
// 更新用户信息data.userInfo
const u = (data?.userInfo ?? data?.user ?? data) as Record<string, unknown> | undefined
if (!u) return
@ -277,7 +296,9 @@ export const useUserStore = defineStore('user', () => {
displayName,
avatarUrl,
balance,
lockedBalance,
positionsValue,
availableAssetValue,
totalAssetValue,
setUser,
logout,