feat(whale-monitor): 保存策略时落库缓存市场并回显标题

- 创建/更新策略时复用 MarketService.getMarkets 写入 markets 表缓存
- 策略 DTO 增加 markets 字段,编辑页直接用其显示市场标题

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WrBug
2026-05-27 05:19:27 +08:00
parent 5d6f0e03f6
commit 1d47cf0451
5 changed files with 101 additions and 6 deletions
@@ -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<String> = emptyList(),
/** 监听市场展示信息(与 conditionIds 顺序一致,保存时写入 markets 缓存) */
val markets: List<WhaleMonitorMarketDto> = emptyList(),
val windowSeconds: Int = 10,
val thresholdAmount: String = "0",
val orderAmount: String = "0",
@@ -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<String>) {
if (conditionIds.isEmpty()) return
marketService.getMarkets(conditionIds)
}
private fun buildMarketDtos(conditionIds: List<String>): List<WhaleMonitorMarketDto> {
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<String> = try {
e.conditionIds.fromJson<List<String>>() ?: 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(),
+21
View File
@@ -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 []
@@ -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,
+10
View File
@@ -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