diff --git a/src/views/TradeDetail.vue b/src/views/TradeDetail.vue index ed8fdcc..d4348dd 100644 --- a/src/views/TradeDetail.vue +++ b/src/views/TradeDetail.vue @@ -53,7 +53,7 @@
-
+
@@ -398,12 +398,11 @@ import { type OpenOrderDisplayItem, } from '../api/order' import { cancelOrder as apiCancelOrder } from '../api/order' +import type { ChartDataPoint, ChartTimeRange } from '../api/chart' import { - normalizeChartData, - fetchChartHistory, - type ChartDataPoint, - type ChartTimeRange, -} from '../api/chart' + getPmPriceHistoryPublic, + priceHistoryToChartData, +} from '../api/priceHistory' import { isCryptoEvent as checkIsCryptoEvent, inferCryptoSymbol, @@ -1242,52 +1241,47 @@ const timeRanges = [ { label: 'ALL', value: 'ALL' }, ] -// 图表数据格式:[时间戳(ms), 概率(0-100)][]。接口约定见 src/api/chart.ts(ChartHistoryParams / ChartHistoryItem / normalizeChartData) -function generateData(range: string): ChartDataPoint[] { - const now = Date.now() - const data: [number, number][] = [] - let stepMs: number - let count: number - switch (range) { - case '1H': - stepMs = 60 * 1000 - count = 60 - break - case '6H': - stepMs = 10 * 60 * 1000 - count = 36 - break - case '1D': - stepMs = 60 * 60 * 1000 - count = 24 - break - case '1W': - stepMs = 24 * 60 * 60 * 1000 - count = 7 - break - case '1M': - case 'ALL': - stepMs = 24 * 60 * 60 * 1000 - count = 30 - break - default: - stepMs = 60 * 60 * 1000 - count = 24 - } - let value = 15 + Math.random() * 25 - for (let i = count; i >= 0; i--) { - const t = now - i * stepMs - value = Math.max(10, Math.min(90, value + (Math.random() - 0.5) * 6)) - data.push([t, Math.round(value * 10) / 10]) - } - return data -} - const chartContainerRef = ref(null) const data = ref<[number, number][]>([]) +/** Yes/No 折线图:接口返回的完整数据(time 已转 ms),用于分时筛选 */ +const rawChartData = ref([]) const cryptoChartLoading = ref(false) +const chartYesNoLoading = ref(false) let chartInstance: ECharts | null = null -let dynamicInterval: number | undefined + +/** 分时范围对应的毫秒数,ALL 返回 null 表示不截断 */ +function getTimeRangeMs(range: string): number | null { + const H = 60 * 60 * 1000 + const D = 24 * H + switch (range) { + case '1H': + return 1 * H + case '6H': + return 6 * H + case '1D': + return 1 * D + case '1W': + return 7 * D + case '1M': + return 30 * D + case 'ALL': + default: + return null + } +} + +/** 按分时范围过滤 [timestamp_ms, value][],保留区间 [now - rangeMs, now] 内的点 */ +function filterChartDataByRange( + points: ChartDataPoint[], + range: string, +): ChartDataPoint[] { + if (!points.length) return [] + const rangeMs = getTimeRangeMs(range) + if (rangeMs == null) return points + const nowMs = Date.now() + const cutoffMs = nowMs - rangeMs + return points.filter(([ts]) => ts >= cutoffMs) +} const currentChance = computed(() => { const ev = eventDetail.value @@ -1523,7 +1517,7 @@ function buildOptionForCrypto( function initChart() { if (!chartContainerRef.value) return - data.value = generateData(selectedTimeRange.value) + data.value = [] chartInstance = echarts.init(chartContainerRef.value) const w = chartContainerRef.value.clientWidth if (chartMode.value === 'crypto') { @@ -1533,12 +1527,15 @@ function initChart() { } } -/** 从接口拉取图表数据(接入时在 updateChartData 中调用并赋给 data.value) */ -async function loadChartFromApi(marketId: string): Promise { - const res = await fetchChartHistory( - { marketID: marketId, range: selectedTimeRange.value as ChartTimeRange } - ) - return normalizeChartData(res.data ?? []) +/** 从 GET /pmPriceHistory/getPmPriceHistoryPublic 拉取价格历史,market 传 YES 对应的 clobTokenId */ +async function loadChartFromApi(marketParam: string): Promise { + const res = await getPmPriceHistoryPublic({ + market: marketParam, + page: 1, + pageSize: 500, + }) + const list = res.data?.list ?? [] + return priceHistoryToChartData(list) } const MINUTE_MS = 60 * 1000 @@ -1566,7 +1563,6 @@ function applyCryptoRealtimePoint(point: [number, number]) { ) } -// 使用接口时:在 updateChartData 内先 await loadChartFromApi(marketId),再 setOption;暂无接口时用 generateData async function updateChartData() { const w = chartContainerRef.value?.clientWidth if (chartMode.value === 'crypto') { @@ -1592,60 +1588,35 @@ async function updateChartData() { } else { cryptoWsUnsubscribe?.() cryptoWsUnsubscribe = null - data.value = generateData(selectedTimeRange.value) - if (chartInstance) - chartInstance.setOption(buildOption(data.value, w), { replaceMerge: ['series'] }) + chartYesNoLoading.value = true + try { + // 价格历史接口的 market 传 clobTokenIds[0](YES 对应 token ID) + const yesTokenId = clobTokenIds.value[0] + const points = yesTokenId ? await loadChartFromApi(yesTokenId) : [] + rawChartData.value = points + data.value = filterChartDataByRange(points, selectedTimeRange.value) + if (chartInstance) + chartInstance.setOption(buildOption(data.value, w), { replaceMerge: ['series'] }) + } finally { + chartYesNoLoading.value = false + } } } function selectTimeRange(range: string) { selectedTimeRange.value = range - updateChartData() } -function getMaxPoints(range: string): number { - switch (range) { - case '1H': - return 60 - case '6H': - return 36 - case '1D': - return 24 - case '1W': - return 7 - case '1M': - case 'ALL': - return 30 - default: - return 24 - } -} - -function startDynamicUpdate() { - dynamicInterval = window.setInterval(() => { - if (chartMode.value === 'crypto') return - const list = [...data.value] - const last = list[list.length - 1] - if (!last) return - const nextVal = Math.max(10, Math.min(90, last[1] + (Math.random() - 0.5) * 4)) - const nextT = Date.now() - list.push([nextT, Math.round(nextVal * 10) / 10]) - const max = getMaxPoints(selectedTimeRange.value) - data.value = list.slice(-max) +watch(selectedTimeRange, (range) => { + if (chartMode.value === 'yesno') { + data.value = filterChartDataByRange(rawChartData.value, range) const w = chartContainerRef.value?.clientWidth if (chartInstance) chartInstance.setOption(buildOption(data.value, w), { replaceMerge: ['series'] }) - }, 3000) -} - -function stopDynamicUpdate() { - if (dynamicInterval) { - clearInterval(dynamicInterval) - dynamicInterval = undefined + } else { + updateChartData() } -} - -watch(selectedTimeRange, () => updateChartData()) +}) // CLOB:当有 market 且存在 clobTokenIds 时连接(使用 Yes/No token ID) const clobTokenIds = computed(() => { @@ -1711,15 +1682,13 @@ const unsubscribePositionUpdate = userStore.onPositionUpdate((data) => { }) onMounted(() => { - loadEventDetail() + loadEventDetail().then(() => updateChartData()) initChart() - startDynamicUpdate() window.addEventListener('resize', handleResize) }) onUnmounted(() => { unsubscribePositionUpdate() - stopDynamicUpdate() cryptoWsUnsubscribe?.() cryptoWsUnsubscribe = null window.removeEventListener('resize', handleResize)