From cb1f43871a7ebd455f4e3c11b2c4c5ae536f10a8 Mon Sep 17 00:00:00 2001 From: WrBug Date: Thu, 26 Feb 2026 20:43:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(crypto-tail):=20=E5=91=A8=E6=9C=9F=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E6=97=B6=E6=8C=89=E5=91=A8=E6=9C=9F=E6=8B=89=E5=8F=96?= =?UTF-8?q?=20tokenIds=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E4=B8=8B=E5=8D=95=20orderbook=20=E4=B8=8D=E5=AD=98=E5=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 后端 initMonitor 支持可选 periodStartUnix,按指定周期取市场与 tokenIds - 前端周期切换时调用 monitorInit 传入 pushPeriod,确保 tokenIds 与当前周期一致 - 修复切换周期无变化及手动下单报 orderbook does not exist Made-with: Cursor --- .../polymarketbot/dto/CryptoTailMonitorDto.kt | 4 +- .../cryptotail/CryptoTailMonitorService.kt | 3 +- frontend/src/pages/CryptoTailMonitor.tsx | 55 ++++++++++++++----- frontend/src/services/api.ts | 4 +- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/CryptoTailMonitorDto.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/CryptoTailMonitorDto.kt index 3761a2e..b279d1d 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/CryptoTailMonitorDto.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/CryptoTailMonitorDto.kt @@ -5,7 +5,9 @@ package com.wrbug.polymarketbot.dto */ data class CryptoTailMonitorInitRequest( /** 策略ID */ - val strategyId: Long = 0L + val strategyId: Long = 0L, + /** 指定周期开始时间 (Unix 秒),不传则用服务器当前周期 */ + val periodStartUnix: Long? = null ) /** diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/cryptotail/CryptoTailMonitorService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/cryptotail/CryptoTailMonitorService.kt index d713be1..e534f76 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/cryptotail/CryptoTailMonitorService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/cryptotail/CryptoTailMonitorService.kt @@ -147,7 +147,8 @@ class CryptoTailMonitorService( val account = accountRepository.findById(strategy.accountId).orElse(null) val nowSeconds = System.currentTimeMillis() / 1000 - val periodStartUnix = (nowSeconds / strategy.intervalSeconds) * strategy.intervalSeconds + val periodStartUnix = request.periodStartUnix + ?: ((nowSeconds / strategy.intervalSeconds) * strategy.intervalSeconds) // 获取市场信息 val slug = "${strategy.marketSlugPrefix}-$periodStartUnix" diff --git a/frontend/src/pages/CryptoTailMonitor.tsx b/frontend/src/pages/CryptoTailMonitor.tsx index c703fc1..57ce647 100644 --- a/frontend/src/pages/CryptoTailMonitor.tsx +++ b/frontend/src/pages/CryptoTailMonitor.tsx @@ -64,6 +64,10 @@ const CryptoTailMonitor: React.FC = () => { const marketChartRef = useRef(null) const marketChartInstance = useRef(null) const lastPeriodStartRef = useRef(null) + const selectedStrategyIdRef = useRef(null) + useEffect(() => { + selectedStrategyIdRef.current = selectedStrategyId + }, [selectedStrategyId]) // localStorage key for period switch mode const PERIOD_SWITCH_MODE_KEY = 'cryptoTailMonitor_periodSwitchMode' @@ -148,7 +152,7 @@ const CryptoTailMonitor: React.FC = () => { setPendingPeriodData(null) setIsViewingOldPeriod(false) try { - const res = await apiService.cryptoTailStrategy.monitorInit(selectedStrategyId) + const res = await apiService.cryptoTailStrategy.monitorInit({ strategyId: selectedStrategyId }) if (res.data.code === 0 && res.data.data) { setInitData(res.data.data) } else { @@ -193,11 +197,23 @@ const CryptoTailMonitor: React.FC = () => { const lastPeriod = lastPeriodStartRef.current if (pushPeriod != null && pushPeriod !== lastPeriod) { - // 新周期到来 + // 新周期到来:重新拉取 init(含 tokenIds),再更新状态 lastPeriodStartRef.current = pushPeriod - + const marketTitle = (data as { marketTitle?: string }).marketTitle + const applyFreshInit = (fresh: CryptoTailMonitorInitResponse) => { + if (selectedStrategyIdRef.current !== fresh.strategyId) return + const merged: CryptoTailMonitorInitResponse = { + ...fresh, + periodStartUnix: pushPeriod, + marketTitle: marketTitle ?? fresh.marketTitle ?? '' + } + if (periodSwitchMode === 'manual' && lastPeriod != null) { + setPendingPeriodData(p => p ? { ...p, initData: merged } : null) + } else { + setInitData(merged) + } + } if (periodSwitchMode === 'manual' && lastPeriod != null) { - // 手动模式:保存新周期数据到 pending,保留当前显示 setPendingPeriodData({ periodStartUnix: pushPeriod, priceHistory: [newPoint], @@ -205,26 +221,35 @@ const CryptoTailMonitor: React.FC = () => { pushData: data }) setIsViewingOldPeriod(true) - // 更新 pending 数据的 initData - setInitData(prev => { - if (prev) { - setPendingPeriodData(p => p ? { ...p, initData: { ...prev, periodStartUnix: pushPeriod, marketTitle: (data as { marketTitle?: string }).marketTitle ?? prev.marketTitle } } : null) + apiService.cryptoTailStrategy.monitorInit({ strategyId: selectedStrategyId!, periodStartUnix: pushPeriod }).then(res => { + if (res.data?.code === 0 && res.data?.data) applyFreshInit(res.data.data) + else { + setInitData(prev => { + if (prev) setPendingPeriodData(p => p ? { ...p, initData: { ...prev, periodStartUnix: pushPeriod, marketTitle: marketTitle ?? prev.marketTitle ?? '' } } : null) + return prev ?? null + }) } - return prev + }).catch(() => { + setInitData(prev => { + if (prev) setPendingPeriodData(p => p ? { ...p, initData: { ...prev, periodStartUnix: pushPeriod, marketTitle: marketTitle ?? prev.marketTitle ?? '' } } : null) + return prev ?? null + }) }) } else { - // 自动模式或首次推送:直接切换 - if (lastPeriod != null) { - setHasSwitchedPeriod(true) - } + if (lastPeriod != null) setHasSwitchedPeriod(true) setFirstDataTime(newPoint.time) - setInitData(prev => prev ? { ...prev, periodStartUnix: pushPeriod, marketTitle: (data as { marketTitle?: string }).marketTitle ?? prev.marketTitle } : null) setPriceHistory([newPoint]) setPushData(data) setIsViewingOldPeriod(false) setPendingPeriodData(null) - return + apiService.cryptoTailStrategy.monitorInit({ strategyId: selectedStrategyId!, periodStartUnix: pushPeriod }).then(res => { + if (res.data?.code === 0 && res.data?.data) applyFreshInit(res.data.data) + else setInitData(prev => prev ? { ...prev, periodStartUnix: pushPeriod, marketTitle: marketTitle ?? prev.marketTitle ?? '' } : null) + }).catch(() => { + setInitData(prev => prev ? { ...prev, periodStartUnix: pushPeriod, marketTitle: marketTitle ?? prev.marketTitle ?? '' } : null) + }) } + return } else { // 同周期:追加数据 if (periodSwitchMode === 'manual' && isViewingOldPeriod && pendingPeriodData) { diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index ac67fa0..3087445 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -498,8 +498,8 @@ export const apiService = { apiClient.post>('/crypto-tail-strategy/market-options', {}), autoMinSpread: (data: { intervalSeconds: number }) => apiClient.post>('/crypto-tail-strategy/auto-min-spread', data), - monitorInit: (strategyId: number) => - apiClient.post>('/crypto-tail-strategy/monitor/init', { strategyId }), + monitorInit: (data: { strategyId: number; periodStartUnix?: number }) => + apiClient.post>('/crypto-tail-strategy/monitor/init', data), manualOrder: (data: { strategyId: number periodStartUnix: number