新增:锁仓信息展示

This commit is contained in:
马丁 2026-05-02 21:37:09 +08:00
parent 10b271e3d8
commit 69c4223af1
7 changed files with 153 additions and 45 deletions

View File

@ -17,6 +17,23 @@ export interface GetPmEarnActivityPublicResponse extends ApiResponse<PmEarnActiv
msg: string
}
/** 个人锁仓情况polymarket.PmMoneyLock */
export interface PmMoneyLock {
ID?: number
userId?: number
locked?: number
freeMoney?: number
unlockDate?: string
typeId?: number
[key: string]: unknown
}
export interface GetLockMoneyResponse extends ApiResponse<PmMoneyLock> {
code: number
data?: PmMoneyLock
msg: string
}
/**
* GET /pmEarnActivity/getPmEarnActivityPublic
*
@ -24,3 +41,13 @@ export interface GetPmEarnActivityPublicResponse extends ApiResponse<PmEarnActiv
export async function getPmEarnActivityPublic(): Promise<GetPmEarnActivityPublicResponse> {
return get<GetPmEarnActivityPublicResponse>('/pmEarnActivity/getPmEarnActivityPublic')
}
/**
* GET /pmMoneyLock/getMyMoneyLock
*
*/
export async function getLockMoney(
config?: { headers?: Record<string, string> },
): Promise<GetLockMoneyResponse> {
return get<GetLockMoneyResponse>('/pmMoneyLock/getMyMoneyLock', undefined, config)
}

View File

@ -435,15 +435,18 @@
"earnActivity": {
"title": "Earn Liquidity",
"subtitle": "Participate to earn extra returns",
"duration": "Duration",
"unlimited": "Unlimited",
"extraProfitRate": "Extra Profit Rate",
"notice": "This page is for viewing only. Please use API for locking operations.",
"tiersTitle": "Profit Tiers",
"minAmount": "Min Amount (USDC)",
"tiersTitle": "Activity Tiers",
"myLockInfo": "My Lock Info",
"lockedAmount": "Locked Amount",
"freeAmount": "Free Amount",
"unlockDate": "Unlock Date",
"tierLevel": "Tier {n}",
"expectedProfit": "Expected Profit",
"days": "{n} Days"
"minAmount": "Min Amount (USDC)",
"expectedProfit": "Expected APY",
"duration": "Duration",
"days": "{n} Days",
"unlimited": "Unlimited",
"notice": "Note: Actual returns may fluctuate based on market conditions. The platform reserves the right of final interpretation."
},
"locale": {
"zh": "简体中文",

View File

@ -435,15 +435,18 @@
"earnActivity": {
"title": "流動性を稼いでロック",
"subtitle": "キャンペーンに参加して追加收益を獲得",
"duration": "期間",
"tiersTitle": "キャンペーンティア",
"myLockInfo": "マイロック情報",
"lockedAmount": "ロック合計額",
"freeAmount": "出金可能額",
"unlockDate": "ロック解除日時",
"tierLevel": "第 {n} ティア",
"minAmount": "最低金額 (USDC)",
"expectedProfit": "予想年利",
"duration": "ロック期間",
"days": "{n} 日",
"unlimited": "無制限",
"extraProfitRate": "追加利益率",
"notice": "このペンは表示のみを目的としています。ロック操作はAPIを通じて行ってください。",
"tiersTitle": "利益ティア",
"minAmount": "最小金額 (USDC)",
"tierLevel": "ティア {n}",
"expectedProfit": "予想利益",
"days": "{n} 日"
"notice": "注意: 実際の収益は市場の状況により変動する場合があります。最終的な解釈権はプラットフォームに帰属します。"
},
"locale": {
"zh": "简体中文",

View File

@ -435,15 +435,18 @@
"earnActivity": {
"title": "유동성 획득 잠금",
"subtitle": "이벤트에 참여하여 추가 수익 획득",
"duration": "기간",
"unlimited": "무제한",
"extraProfitRate": "추가 이익률",
"notice": "이 페이지는 조회 전용입니다. 잠금 작업은 API를 통해 진행해 주세요.",
"tiersTitle": "수익 티어",
"minAmount": "최소 금액 (USDC)",
"tiersTitle": "이벤트 티어",
"myLockInfo": "내 잠금 정보",
"lockedAmount": "전체 잠금 금액",
"freeAmount": "출금 가능 금액",
"unlockDate": "잠금 해제 시간",
"tierLevel": "티어 {n}",
"expectedProfit": "예상 수익",
"days": "{n}일"
"minAmount": "최소 금액 (USDC)",
"expectedProfit": "예상 연수익률",
"duration": "잠금 기간",
"days": "{n}일",
"unlimited": "무제한",
"notice": "주의: 실제 수익은 시장 상황에 따라 변동될 수 있습니다. 최종 해석 권한은 플랫폼에 있습니다."
},
"locale": {
"zh": "简体中文",

View File

@ -447,15 +447,18 @@
"earnActivity": {
"title": "锁仓赚取流动性",
"subtitle": "参与活动获得额外收益",
"duration": "活动时长",
"unlimited": "不限时",
"extraProfitRate": "额外利润比例",
"notice": "此页面仅供查看,锁仓操作请通过 API 进行。",
"tiersTitle": "收益挡位",
"minAmount": "最小金额 (USDC)",
"tierLevel": "挡位 {n}",
"expectedProfit": "预期利润",
"days": "{n} 天"
"tiersTitle": "活动档位",
"myLockInfo": "我的锁仓情况",
"lockedAmount": "当前流动性锁仓金额",
"freeAmount": "可提现金额",
"unlockDate": "解锁时间",
"tierLevel": "第 {n} 档",
"minAmount": "起存金额 (USDC)",
"expectedProfit": "预期年化",
"duration": "锁仓期限",
"days": "{n} 天",
"unlimited": "无限制",
"notice": "注意:实际收益可能会根据市场情况有所波动,最终解释权归平台所有。"
},
"locale": {
"zh": "简体中文",

View File

@ -435,15 +435,18 @@
"earnActivity": {
"title": "鎖倉賺取流動性",
"subtitle": "參與活動獲得額外收益",
"duration": "活動時長",
"unlimited": "不限時",
"extraProfitRate": "額外利潤比例",
"notice": "此頁面僅供查看,鎖倉操作請透過 API 進行。",
"tiersTitle": "收益檔位",
"minAmount": "最小金額 (USDC)",
"tierLevel": "檔位 {n}",
"expectedProfit": "預期利潤",
"days": "{n} 天"
"tiersTitle": "活動檔位",
"myLockInfo": "我的鎖倉情況",
"lockedAmount": "當前流動性鎖倉金額",
"freeAmount": "可提現金額",
"unlockDate": "解鎖時間",
"tierLevel": "第 {n} 檔",
"minAmount": "起存金額 (USDC)",
"expectedProfit": "預期年化",
"duration": "鎖倉期限",
"days": "{n} 天",
"unlimited": "無限制",
"notice": "注意:實際收益可能會根據市場情況有所波動,最終解釋權歸平台所有。"
},
"locale": {
"zh": "繁體中文",

View File

@ -9,6 +9,29 @@
<p class="header-sub">{{ t('earnActivity.subtitle') }}</p>
</section>
<section class="card lock-info-card" v-if="userStore.isLoggedIn">
<h2 class="tiers-title">{{ t('earnActivity.myLockInfo') }}</h2>
<div class="lock-info-content" v-if="!lockLoading">
<div class="info-row">
<span class="info-label">{{ t('earnActivity.lockedAmount') }}</span>
<span class="info-value highlight">{{ formatAmount(lockInfo?.locked) }}</span>
</div>
<div class="info-divider"></div>
<div class="info-row">
<span class="info-label">{{ t('earnActivity.freeAmount') }}</span>
<span class="info-value">{{ formatAmount(lockInfo?.freeMoney) }}</span>
</div>
<div class="info-divider"></div>
<div class="info-row">
<span class="info-label">{{ t('earnActivity.unlockDate') }}</span>
<span class="info-value">{{ formatUnlockDate(lockInfo?.unlockDate) }}</span>
</div>
</div>
<div v-else class="lock-loading">
<v-progress-circular indeterminate size="24" width="2" color="#5b5bd6" />
</div>
</section>
<section class="card tiers-card" v-if="activityList.length > 0">
<h2 class="tiers-title">{{ t('earnActivity.tiersTitle') }}</h2>
<div class="tier-list">
@ -19,7 +42,7 @@
<div class="tier-content">
<div class="info-row">
<span class="info-label">{{ t('earnActivity.minAmount') }}</span>
<span class="info-value">{{ item.minAmount ? item.minAmount.toLocaleString() : '--' }}</span>
<span class="info-value">{{ formatAmount(item.minAmount) }}</span>
</div>
<div class="info-divider"></div>
<div class="info-row">
@ -49,14 +72,26 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { getPmEarnActivityPublic } from '@/api/earnActivity'
import type { PmEarnActivityItem } from '@/api/earnActivity'
import { getPmEarnActivityPublic, getLockMoney } from '@/api/earnActivity'
import type { PmEarnActivityItem, PmMoneyLock } from '@/api/earnActivity'
import { useUserStore } from '@/stores/user'
const { t } = useI18n()
const userStore = useUserStore()
const activityList = ref<PmEarnActivityItem[]>([])
const loading = ref(false)
const lockInfo = ref<PmMoneyLock | null>(null)
const lockLoading = ref(false)
const formatAmount = (val: number | string | undefined | null) => {
if (val == null) return '0'
const num = typeof val === 'string' ? parseFloat(val) : val
if (!Number.isFinite(num)) return '0'
return Math.floor(num / 1000000).toLocaleString()
}
const formatRate = (rate: number | null) => {
if (!rate) return '--'
return `${(rate * 100).toFixed(0)}%`
@ -68,6 +103,11 @@ const formatDuration = (seconds: number | null) => {
return t('earnActivity.days', { n: days })
}
const formatUnlockDate = (dateStr: string | undefined | null) => {
if (!dateStr || dateStr === '0001-01-01T00:00:00Z') return '--'
return new Date(dateStr).toLocaleString()
}
onMounted(async () => {
loading.value = true
try {
@ -80,7 +120,27 @@ onMounted(async () => {
} finally {
loading.value = false
}
if (userStore.isLoggedIn) {
fetchLockInfo()
}
})
async function fetchLockInfo() {
const headers = userStore.getAuthHeaders()
if (!headers) return
lockLoading.value = true
try {
const res = await getLockMoney({ headers })
if (res.code === 0 && res.data) {
lockInfo.value = res.data
}
} catch (error) {
console.error('Failed to fetch lock info:', error)
} finally {
lockLoading.value = false
}
}
</script>
<style scoped>
@ -213,6 +273,12 @@ onMounted(async () => {
background: #e5e7eb;
}
.lock-loading {
display: flex;
justify-content: center;
padding: 16px 0;
}
.notice-card {
display: flex;
align-items: flex-start;