This commit is contained in:
薇薇安 2026-01-15 16:58:05 +08:00
parent db2bd6a3b2
commit 2e672d1f25
3 changed files with 83 additions and 7 deletions

View File

@ -118,10 +118,22 @@ async def get_active_recommendations():
""" """
获取当前有效的推荐未过期未执行未取消 获取当前有效的推荐未过期未执行未取消
使用WebSocket实时价格更新推荐中的价格信息 使用WebSocket实时价格更新推荐中的价格信息
同一交易对只返回最新的推荐已去重
""" """
try: try:
recommendations = TradeRecommendation.get_active() recommendations = TradeRecommendation.get_active()
# 确保时间格式正确转换为ISO格式字符串包含时区信息
from datetime import datetime
for rec in recommendations:
if rec.get('recommendation_time'):
if isinstance(rec['recommendation_time'], datetime):
# 如果是datetime对象转换为ISO格式字符串UTC+8
rec['recommendation_time'] = rec['recommendation_time'].isoformat()
elif isinstance(rec['recommendation_time'], str):
# 如果已经是字符串,确保格式正确
pass
# 尝试从WebSocket缓存获取实时价格更新推荐中的价格 # 尝试从WebSocket缓存获取实时价格更新推荐中的价格
try: try:
import sys import sys

View File

@ -322,11 +322,19 @@ class TradeRecommendation:
@staticmethod @staticmethod
def get_active(): def get_active():
"""获取当前有效的推荐(未过期、未执行、未取消)""" """获取当前有效的推荐(未过期、未执行、未取消)
同一交易对只返回最新的推荐去重
"""
return db.execute_query( return db.execute_query(
"""SELECT * FROM trade_recommendations """SELECT t1.* FROM trade_recommendations t1
INNER JOIN (
SELECT symbol, MAX(recommendation_time) as max_time
FROM trade_recommendations
WHERE status = 'active' AND (expires_at IS NULL OR expires_at > NOW()) WHERE status = 'active' AND (expires_at IS NULL OR expires_at > NOW())
ORDER BY signal_strength DESC, recommendation_time DESC""" GROUP BY symbol
) t2 ON t1.symbol = t2.symbol AND t1.recommendation_time = t2.max_time
WHERE t1.status = 'active' AND (t1.expires_at IS NULL OR t1.expires_at > NOW())
ORDER BY t1.signal_strength DESC, t1.recommendation_time DESC"""
) )
@staticmethod @staticmethod

View File

@ -14,10 +14,56 @@ function Recommendations() {
useEffect(() => { useEffect(() => {
loadRecommendations() loadRecommendations()
// 10 // 10loading
let interval = null let interval = null
if (statusFilter === 'active') { if (statusFilter === 'active') {
interval = setInterval(loadRecommendations, 10000) // 10 interval = setInterval(async () => {
// loading
try {
const result = await api.getActiveRecommendations()
const newData = result.data || []
// 使setStateloading
setRecommendations(prevRecommendations => {
//
if (newData.length === 0) {
return prevRecommendations
}
//
const newDataMap = new Map(newData.map(rec => [rec.id, rec]))
const prevMap = new Map(prevRecommendations.map(rec => [rec.id, rec]))
// 使
const updated = prevRecommendations.map(prevRec => {
const newRec = newDataMap.get(prevRec.id)
if (newRec) {
// 使
return newRec
}
//
return prevRec
})
//
const newItems = newData.filter(newRec => !prevMap.has(newRec.id))
// id
const merged = [...updated, ...newItems]
const uniqueMap = new Map()
merged.forEach(rec => {
if (!uniqueMap.has(rec.id)) {
uniqueMap.set(rec.id, rec)
}
})
return Array.from(uniqueMap.values())
})
} catch (err) {
//
console.debug('静默更新价格失败:', err)
}
}, 10000) // 10
} }
return () => { return () => {
@ -104,14 +150,24 @@ function Recommendations() {
const formatTime = (timeStr) => { const formatTime = (timeStr) => {
if (!timeStr) return '-' if (!timeStr) return '-'
try { try {
//
// UTC
const date = new Date(timeStr) const date = new Date(timeStr)
//
if (isNaN(date.getTime())) {
return timeStr
}
// 使UTC
return date.toLocaleString('zh-CN', { return date.toLocaleString('zh-CN', {
year: 'numeric', year: 'numeric',
month: '2-digit', month: '2-digit',
day: '2-digit', day: '2-digit',
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit',
second: '2-digit' second: '2-digit',
timeZone: 'Asia/Shanghai' // 使
}) })
} catch (e) { } catch (e) {
return timeStr return timeStr