From 1d47cf04514d5d9311b4e52c56a356776dc05b01 Mon Sep 17 00:00:00 2001 From: WrBug Date: Wed, 27 May 2026 05:19:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(whale-monitor):=20=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E7=AD=96=E7=95=A5=E6=97=B6=E8=90=BD=E5=BA=93=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=B8=82=E5=9C=BA=E5=B9=B6=E5=9B=9E=E6=98=BE=E6=A0=87=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建/更新策略时复用 MarketService.getMarkets 写入 markets 表缓存 - 策略 DTO 增加 markets 字段,编辑页直接用其显示市场标题 Co-authored-by: Cursor --- .../dto/WhaleMonitorStrategyDto.kt | 14 +++++++ .../WhaleMonitorStrategyService.kt | 39 +++++++++++++++++-- frontend/src/constants/whaleMonitor.ts | 21 ++++++++++ .../src/pages/WhaleMonitorStrategyList.tsx | 23 +++++++++-- frontend/src/types/index.ts | 10 +++++ 5 files changed, 101 insertions(+), 6 deletions(-) diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/WhaleMonitorStrategyDto.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/WhaleMonitorStrategyDto.kt index 0aca4f6..cdfb219 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/WhaleMonitorStrategyDto.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/dto/WhaleMonitorStrategyDto.kt @@ -44,6 +44,18 @@ data class WhaleMonitorStrategyListRequest( val enabled: Boolean? = null ) +/** + * 策略关联市场展示信息(来自 markets 表缓存) + */ +data class WhaleMonitorMarketDto( + val conditionId: String = "", + val title: String = "", + val slug: String? = null, + val category: String? = null, + val image: String? = null, + val icon: String? = null +) + /** * 大单监听策略 DTO(列表与详情) */ @@ -52,6 +64,8 @@ data class WhaleMonitorStrategyDto( val accountId: Long = 0L, val name: String? = null, val conditionIds: List = emptyList(), + /** 监听市场展示信息(与 conditionIds 顺序一致,保存时写入 markets 缓存) */ + val markets: List = emptyList(), val windowSeconds: Int = 10, val thresholdAmount: String = "0", val orderAmount: String = "0", diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/whalemonitor/WhaleMonitorStrategyService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/whalemonitor/WhaleMonitorStrategyService.kt index 9a77f90..f12b31f 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/whalemonitor/WhaleMonitorStrategyService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/whalemonitor/WhaleMonitorStrategyService.kt @@ -7,6 +7,7 @@ import com.wrbug.polymarketbot.enums.ErrorCode import com.wrbug.polymarketbot.event.WhaleMonitorStrategyChangedEvent import com.wrbug.polymarketbot.repository.WhaleMonitorStrategyRepository import com.wrbug.polymarketbot.repository.WhaleMonitorTriggerRepository +import com.wrbug.polymarketbot.service.common.MarketService import com.wrbug.polymarketbot.util.fromJson import com.wrbug.polymarketbot.util.gt import com.wrbug.polymarketbot.util.toSafeBigDecimal @@ -26,6 +27,7 @@ import java.time.format.DateTimeFormatter class WhaleMonitorStrategyService( private val strategyRepository: WhaleMonitorStrategyRepository, private val triggerRepository: WhaleMonitorTriggerRepository, + private val marketService: MarketService, private val eventPublisher: ApplicationEventPublisher ) { @@ -63,6 +65,7 @@ class WhaleMonitorStrategyService( validatePriceDecimalPlaces(maxPrice, "maxPrice") val conditionIdsJson = request.conditionIds.toJson() + cacheMarkets(request.conditionIds) val nameToSave = request.name?.takeIf { it.isNotBlank() } ?: generateStrategyName() @@ -95,10 +98,13 @@ class WhaleMonitorStrategyService( val existing = strategyRepository.findById(request.strategyId).orElse(null) ?: return Result.failure(IllegalArgumentException(ErrorCode.WHALE_MONITOR_STRATEGY_NOT_FOUND.messageKey)) - val conditionIdsJson = request.conditionIds?.let { + val updatedConditionIds = request.conditionIds?.also { if (it.isEmpty()) return Result.failure(IllegalArgumentException(ErrorCode.WHALE_MONITOR_STRATEGY_CONDITION_IDS_EMPTY.messageKey)) - it.toJson() - } ?: existing.conditionIds + } + val conditionIdsJson = updatedConditionIds?.toJson() ?: existing.conditionIds + if (updatedConditionIds != null) { + cacheMarkets(updatedConditionIds) + } val windowSeconds = request.windowSeconds ?: existing.windowSeconds if (windowSeconds <= 0) { @@ -251,6 +257,32 @@ class WhaleMonitorStrategyService( return "大单监听策略-$suffix" } + /** 将 conditionId 对应市场写入 markets 表(复用 MarketService 缓存与 Gamma 拉取) */ + private fun cacheMarkets(conditionIds: List) { + if (conditionIds.isEmpty()) return + marketService.getMarkets(conditionIds) + } + + private fun buildMarketDtos(conditionIds: List): List { + if (conditionIds.isEmpty()) return emptyList() + val cached = marketService.getMarkets(conditionIds) + return conditionIds.map { id -> + val market = cached[id] + if (market != null) { + WhaleMonitorMarketDto( + conditionId = id, + title = market.title, + slug = market.slug, + category = market.category, + image = market.image, + icon = market.icon + ) + } else { + WhaleMonitorMarketDto(conditionId = id, title = id) + } + } + } + private fun entityToDto(e: WhaleMonitorStrategy, lastTriggerAt: Long?, triggerCount: Long): WhaleMonitorStrategyDto { val conditionIdList: List = try { e.conditionIds.fromJson>() ?: emptyList() @@ -262,6 +294,7 @@ class WhaleMonitorStrategyService( accountId = e.accountId, name = e.name, conditionIds = conditionIdList, + markets = buildMarketDtos(conditionIdList), windowSeconds = e.windowSeconds, thresholdAmount = e.thresholdAmount.toPlainString(), orderAmount = e.orderAmount.toPlainString(), diff --git a/frontend/src/constants/whaleMonitor.ts b/frontend/src/constants/whaleMonitor.ts index ff9913a..f35533f 100644 --- a/frontend/src/constants/whaleMonitor.ts +++ b/frontend/src/constants/whaleMonitor.ts @@ -30,6 +30,27 @@ export function conditionIdsToMarkets( }) } +/** 策略列表/详情中的 markets 字段转为表单展示项 */ +export function strategyMarketsToItems( + markets: Array<{ + conditionId: string + title: string + slug?: string + category?: string + image?: string + icon?: string + }> +): WhaleMonitorMarketItem[] { + return markets.map(m => ({ + conditionId: m.conditionId, + title: m.title, + slug: m.slug, + category: m.category, + image: m.image, + icon: m.icon + })) +} + /** 解析 Gamma 返回的 outcomes JSON 字符串 */ export function parseMarketOutcomes(outcomes?: string): string[] { if (!outcomes?.trim()) return [] diff --git a/frontend/src/pages/WhaleMonitorStrategyList.tsx b/frontend/src/pages/WhaleMonitorStrategyList.tsx index bddc680..4f70fb8 100644 --- a/frontend/src/pages/WhaleMonitorStrategyList.tsx +++ b/frontend/src/pages/WhaleMonitorStrategyList.tsx @@ -10,7 +10,8 @@ import { clearWhaleMonitorFormDraft, conditionIdsToMarkets, loadWhaleMonitorFormDraft, - saveWhaleMonitorFormDraft + saveWhaleMonitorFormDraft, + strategyMarketsToItems } from '../constants/whaleMonitor' import type { WhaleMonitorStrategyDto, @@ -90,7 +91,19 @@ const WhaleMonitorStrategyList: React.FC = () => { } else { setEditingStrategy(null) } - setSelectedMarkets(pendingFormDraft.selectedMarkets) + const draftStrategy = pendingFormDraft.editingStrategyId + ? strategies.find(s => s.id === pendingFormDraft.editingStrategyId) + : undefined + const knownMarkets = + draftStrategy?.markets && draftStrategy.markets.length > 0 + ? strategyMarketsToItems(draftStrategy.markets) + : pendingFormDraft.selectedMarkets + setSelectedMarkets( + conditionIdsToMarkets( + draftStrategy?.conditionIds ?? knownMarkets.map(m => m.conditionId), + knownMarkets + ) + ) form.setFieldsValue(pendingFormDraft.formValues) setFormVisible(true) setPendingFormDraft(null) @@ -173,7 +186,11 @@ const WhaleMonitorStrategyList: React.FC = () => { const showEditModal = (strategy: WhaleMonitorStrategyDto) => { setEditingStrategy(strategy) - setSelectedMarkets(conditionIdsToMarkets(strategy.conditionIds)) + const known = + strategy.markets && strategy.markets.length > 0 + ? strategyMarketsToItems(strategy.markets) + : [] + setSelectedMarkets(conditionIdsToMarkets(strategy.conditionIds, known)) form.setFieldsValue({ accountId: strategy.accountId, name: strategy.name, diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 0f649cb..1875c61 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -1344,11 +1344,21 @@ export interface WhaleMonitorStrategyListLocationState { selectedMarkets?: WhaleMonitorMarketItem[] } +export interface WhaleMonitorStrategyMarketDto { + conditionId: string + title: string + slug?: string + category?: string + image?: string + icon?: string +} + export interface WhaleMonitorStrategyDto { id: number accountId: number name?: string conditionIds: string[] + markets?: WhaleMonitorStrategyMarketDto[] windowSeconds: number thresholdAmount: string orderAmount: string