diff --git a/docs/api/historyRecord.md b/docs/api/historyRecord.md index 22fd93b..840fa28 100644 --- a/docs/api/historyRecord.md +++ b/docs/api/historyRecord.md @@ -59,17 +59,16 @@ | 字段 | 类型 | 说明 | |------|------|------| | ID | number | 主键 | -| title | string | 标题 | -| name | string | 名称 | -| eventSlug | string | 事件标识 | -| outcome | string | 结果(Yes/No 等) | -| side | string | 方向 | -| type | string | 类型 | +| title | string | 标题(如「充值资金」) | +| type | string | 类型(如 recharge) | +| **usdcSize** | number | **金额(USDC)**,用于充值等 | +| **icon** | string | **图标路径**(如 uploads/file/btc.png),会转为完整 URL 展示 | +| **UpdatedAt** | string | **更新时间**,用于 timeAgo 展示 | | price | number | 价格 | | size | number | 大小 | -| createdAt | string | 创建时间 | -| timestamp | number | 时间戳(秒) | -| 其他 | - | asset, bio, conditionId, icon, slug, transactionHash 等 | +| outcome | string | 结果 | +| timestamp | number | 时间戳(秒或毫秒) | +| 其他 | - | asset, bio, conditionId, slug, transactionHash 等 | ## 使用方式 diff --git a/docs/api/priceHistory.md b/docs/api/priceHistory.md index b8a5070..f9b5aeb 100644 --- a/docs/api/priceHistory.md +++ b/docs/api/priceHistory.md @@ -9,6 +9,7 @@ ## 核心能力 - `getPmPriceHistoryPublic`:按市场 ID 分页获取价格历史 +- `getTimeRangeSeconds`:根据分时范围计算 `startTs`、`endTs`(Unix 秒);`endTs` 始终为当前时间;1H/6H/1D/1W/1M 的 `startTs` 为当前时间往前对应时长;ALL 的 `startTs` 为事件开始时间、`endTs` 为当前时间 - `priceHistoryToChartData`:将接口返回的 `list` 转为 ECharts 使用的 `[timestamp_ms, value_0_100][]` ## GET /pmPriceHistory/getPmPriceHistoryPublic @@ -20,6 +21,8 @@ | market | string | 是 | 传 YES 对应的 clobTokenId(即当前市场 clobTokenIds[0]) | | page | number | 否 | 页码,默认 1 | | pageSize | number | 否 | 每页条数,默认 500 | +| startTs | number | 否 | 时间范围起始(Unix 秒) | +| endTs | number | 否 | 时间范围结束(Unix 秒) | | interval | string | 否 | 数据间隔 | | time | number | 否 | 时间筛选 | | createdAtRange | string[] | 否 | 创建时间范围 | @@ -52,18 +55,22 @@ import { getPmPriceHistoryPublic, priceHistoryToChartData, + getTimeRangeSeconds, type PmPriceHistoryItem, } from '@/api/priceHistory' +const timeRange = getTimeRangeSeconds('1D') // { startTs, endTs } +// ALL 时传 eventDates:getTimeRangeSeconds('ALL', { startDate: ev.startDate, endDate: ev.endDate }) const res = await getPmPriceHistoryPublic({ market: marketId, page: 1, pageSize: 500, + ...(timeRange && { startTs: timeRange.startTs, endTs: timeRange.endTs }), }) const chartData = priceHistoryToChartData(res.data?.list ?? []) ``` ## 扩展方式 -- 按时间范围(1H/6H/1D 等)传 `interval` 或 `createdAtRange` 需与后端约定取值 +- 时间戳规则:`endTs` 始终为当前时间;1H/6H/1D/1W/1M 的 `startTs` 为当前时间往前对应时长;ALL 的 `startTs` 为事件 `startDate`,`endTs` 为当前时间 - 若后端返回的 `price` 固定为 0–100,`priceHistoryToChartData` 已兼容(≤1 时乘 100) diff --git a/docs/views/EventMarkets.md b/docs/views/EventMarkets.md index 2951375..6fdbcde 100644 --- a/docs/views/EventMarkets.md +++ b/docs/views/EventMarkets.md @@ -7,12 +7,17 @@ 事件下的市场列表页,展示某个 Event 的多个 Market(如 NFL 多支队伍),支持选择并跳转交易详情。 +- **多市场折线图**:按市场数量依次调用 `getPmPriceHistoryPublic`,每个市场使用 `clobTokenIds[0]`(YES token)作为 `market` 参数,展示多条分时曲线 +- **时间范围**:1H / 6H / 1D / 1W / 1M / ALL,与 TradeDetail 一致 + ## 使用方式 - 从首页或详情进入,路由 `/event/123/markets` - 路由参数 `id` 为 Event ID +- 分时图数据来源:`src/api/priceHistory.ts` 的 `getPmPriceHistoryPublic`、`priceHistoryToChartData` ## 扩展方式 - 增加市场筛选、排序 - 与 TradeDetail 联动,支持从市场列表直接进入指定 market 的交易 +- 可抽取 `getTimeRangeMs`、`filterChartDataByRange` 为共享 util,与 TradeDetail 复用 diff --git a/src/api/historyRecord.ts b/src/api/historyRecord.ts index 09d1c48..2d29c0f 100644 --- a/src/api/historyRecord.ts +++ b/src/api/historyRecord.ts @@ -4,6 +4,7 @@ */ import { buildQuery, get } from './request' +import { BASE_URL } from './request' import type { PageResult } from './types' /** 单条历史记录(与 doc.json definitions["polymarket.HistoryRecord"] 对齐) */ @@ -13,6 +14,7 @@ export interface HistoryRecordItem { bio?: string conditionId?: string createdAt?: string + CreatedAt?: string eventSlug?: string icon?: string name?: string @@ -31,6 +33,9 @@ export interface HistoryRecordItem { transactionHash?: string type?: string updatedAt?: string + UpdatedAt?: string + /** 金额(USDC),用于充值等类型 */ + usdcSize?: number } /** GET /hr/getHistoryRecordPublic 请求参数 */ @@ -129,11 +134,15 @@ export interface HistoryDisplayItem { shares?: string iconChar?: string iconClass?: string + /** 图标 URL(来自 record.icon,用于展示) */ + imageUrl?: string } -function formatTimeAgo(createdAt: string | undefined, timestamp?: number): string { - const ms = createdAt ? new Date(createdAt).getTime() : (timestamp != null ? timestamp * 1000 : 0) - if (!ms) return '' +function formatTimeAgo(dateStr: string | undefined, timestamp?: number): string { + let ms = 0 + if (dateStr) ms = new Date(dateStr).getTime() + else if (timestamp != null) ms = timestamp < 1e12 ? timestamp * 1000 : timestamp + if (!ms || !Number.isFinite(ms)) return '' const diff = Date.now() - ms if (diff < 60000) return 'Just now' if (diff < 3600000) return `${Math.floor(diff / 60000)} minutes ago` @@ -142,8 +151,18 @@ function formatTimeAgo(createdAt: string | undefined, timestamp?: number): strin return new Date(ms).toLocaleDateString() } +/** 将相对路径转为完整 URL */ +function toFullIconUrl(icon: string | undefined): string | undefined { + if (!icon?.trim()) return undefined + const s = icon.trim() + if (s.startsWith('http://') || s.startsWith('https://')) return s + const base = BASE_URL?.replace(/\/$/, '') ?? '' + return `${base}/${s.replace(/^\//, '')}` +} + /** * 将 HistoryRecordItem 映射为钱包 History 展示项 + * 金额用 usdcSize,图标用 icon,日期用 UpdatedAt */ export function mapHistoryRecordToDisplayItem(record: HistoryRecordItem): HistoryDisplayItem { const id = String(record.ID ?? '') @@ -152,13 +171,18 @@ export function mapHistoryRecordToDisplayItem(record: HistoryRecordItem): Histor const side = outcome === 'No' || outcome === 'Down' ? 'No' : 'Yes' const typeLabel = record.type ?? 'Trade' const activity = `${typeLabel} ${outcome}`.trim() + const usdcSize = record.usdcSize ?? 0 const price = record.price ?? 0 const size = record.size ?? 0 - const valueUsd = price * size + const valueUsd = usdcSize !== 0 ? usdcSize : price * size const value = `$${Math.abs(valueUsd).toFixed(2)}` const priceCents = Math.round(price * 100) const activityDetail = size > 0 ? `Sold ${Math.floor(size)} ${outcome} at ${priceCents}¢` : value - const timeAgo = formatTimeAgo(record.createdAt, record.timestamp) + const timeAgo = formatTimeAgo( + record.UpdatedAt ?? record.updatedAt ?? record.CreatedAt ?? record.createdAt, + record.timestamp, + ) + const imageUrl = toFullIconUrl(record.icon) return { id, market, @@ -171,6 +195,7 @@ export function mapHistoryRecordToDisplayItem(record: HistoryRecordItem): Histor timeAgo, avgPrice: priceCents ? `${priceCents}¢` : undefined, shares: size > 0 ? String(Math.floor(size)) : undefined, + imageUrl, } } diff --git a/src/api/priceHistory.ts b/src/api/priceHistory.ts index 92d8aa8..28892bf 100644 --- a/src/api/priceHistory.ts +++ b/src/api/priceHistory.ts @@ -28,6 +28,10 @@ export interface GetPmPriceHistoryPublicParams { market: string page?: number pageSize?: number + /** 时间范围:起始时间戳(Unix 秒) */ + startTs?: number + /** 时间范围:结束时间戳(Unix 秒) */ + endTs?: number /** 数据间隔 */ interval?: string /** 时间筛选 */ @@ -56,11 +60,13 @@ export async function getPmPriceHistoryPublic( params: GetPmPriceHistoryPublicParams, config?: { headers?: Record }, ): Promise { - const { market, page = 1, pageSize = 500, interval, time, createdAtRange, fidelity, keyword, order, sort, price } = params + const { market, page = 1, pageSize = 500, startTs, endTs, interval, time, createdAtRange, fidelity, keyword, order, sort, price } = params const query = buildQuery({ market, page, pageSize, + startTs, + endTs, interval, time, createdAtRange, @@ -76,6 +82,34 @@ export async function getPmPriceHistoryPublic( /** 图表单点格式 [timestamp_ms, value_0_100] */ export type ChartDataPoint = [number, number] +/** + * 分时范围对应的 Unix 秒时间戳 + * 规则:endTs 始终为当前时间;1H/6H/1D/1W/1M 的 startTs 为当前时间往前对应时长;ALL 的 startTs 为事件开始时间、endTs 为当前时间 + */ +export function getTimeRangeSeconds( + range: string, + eventDates?: { startDate?: string; endDate?: string }, +): { startTs: number; endTs: number } | null { + const nowSec = Math.floor(Date.now() / 1000) + const H = 60 * 60 + const D = 24 * H + switch (range) { + case '1H': return { startTs: nowSec - 1 * H, endTs: nowSec } + case '6H': return { startTs: nowSec - 6 * H, endTs: nowSec } + case '1D': return { startTs: nowSec - 1 * D, endTs: nowSec } + case '1W': return { startTs: nowSec - 7 * D, endTs: nowSec } + case '1M': return { startTs: nowSec - 30 * D, endTs: nowSec } + case 'ALL': + if (eventDates?.startDate) { + const startTs = Math.floor(new Date(eventDates.startDate).getTime() / 1000) + if (Number.isFinite(startTs)) + return { startTs, endTs: nowSec } + } + return null + default: return null + } +} + /** * 将接口返回的 list 转为 ECharts 折线图数据 * - time 转为毫秒时间戳 diff --git a/src/components/DepositDialog.vue b/src/components/DepositDialog.vue index 6170bef..aaa42b6 100644 --- a/src/components/DepositDialog.vue +++ b/src/components/DepositDialog.vue @@ -296,7 +296,7 @@ async function checkBalance(isFirst = false) { for (const addr of contractsToCheck) { try { const contract = new ethers.Contract(addr, ['function balanceOf(address) view returns (uint256)'], provider) - const bal = await contract.balanceOf(targetAddr) + const bal = contract.balanceOf ? await contract.balanceOf(targetAddr) : BigInt(0) totalBalance += bal } catch (err) { console.warn(`Failed to check balance for token ${addr}`, err) diff --git a/src/components/TradeComponent.vue b/src/components/TradeComponent.vue index f1c005c..52f82f7 100644 --- a/src/components/TradeComponent.vue +++ b/src/components/TradeComponent.vue @@ -1579,7 +1579,7 @@ async function submitMerge() { mergeError.value = '' try { const res = await pmMarketMerge( - { marketID: marketId, amount: String(mergeAmount.value) }, + { marketID: marketId, amount: (mergeAmount.value * 1000000).toFixed(0) }, { headers: userStore.getAuthHeaders() }, ) if (res.code === 0 || res.code === 200) { @@ -1614,7 +1614,7 @@ async function submitSplit() { splitError.value = '' try { const res = await pmMarketSplit( - { marketID: marketId, usdcAmount: String(splitAmount.value * 1000000) }, + { marketID: marketId, usdcAmount: (splitAmount.value * 1000000).toFixed(0) }, { headers: userStore.getAuthHeaders() }, ) if (res.code === 0 || res.code === 200) { diff --git a/src/views/EventMarkets.vue b/src/views/EventMarkets.vue index bbb85fd..4c0f912 100644 --- a/src/views/EventMarkets.vue +++ b/src/views/EventMarkets.vue @@ -36,6 +36,9 @@

{{ markets.length }} 个市场

+
+ +