diff --git a/app.py b/app.py
index b37c2f35..828de135 100755
--- a/app.py
+++ b/app.py
@@ -11004,9 +11004,12 @@ def get_events_effectiveness_stats():
按交易日统计事件数据,展示事件预测的有效性
+ 交易日定义:上一交易日15:00到当前交易日15:00
+ 例如:周一15:00到周二15:00为"周二交易日"的事件
+
参数:
date: 指定日期(YYYY-MM-DD格式,可选,默认今天)
- days: 统计天数(默认7天)
+ days: 统计天数(默认7天,days=1表示当前交易日)
返回:
{
@@ -11041,21 +11044,78 @@ def get_events_effectiveness_stats():
days = request.args.get('days', 7, type=int)
days = min(max(days, 1), 30) # 限制1-30天
- # 确定查询日期范围
+ # 确定基准时间
if date_str:
try:
- end_date = datetime.strptime(date_str, '%Y-%m-%d')
+ base_date = datetime.strptime(date_str, '%Y-%m-%d')
except ValueError:
- end_date = datetime.now()
+ base_date = datetime.now()
else:
- end_date = datetime.now()
+ base_date = datetime.now()
- start_date = end_date - timedelta(days=days)
+ # 使用交易日15:00作为分界点计算时间范围
+ # 当前交易日的结束时间:当天15:00(如果当前时间<15:00)或下一交易日15:00(如果当前时间>=15:00)
+ current_time = base_date.time() if isinstance(base_date, datetime) else dt_time(12, 0)
+ current_date = base_date.date() if isinstance(base_date, datetime) else base_date
+
+ # 确保交易日数据已加载
+ if not trading_days:
+ load_trading_days()
+
+ # 判断当前是否是交易日以及是否收盘后
+ is_trading = current_date in trading_days_set
+ is_after_close = current_time >= dt_time(15, 0)
+
+ # 确定当前交易日
+ if is_trading:
+ if is_after_close:
+ # 交易日收盘后,当前交易日就是今天
+ current_trading_day = current_date
+ else:
+ # 交易日盘中,当前交易日是今天
+ current_trading_day = current_date
+ else:
+ # 非交易日,找最近的上一个交易日
+ current_trading_day = None
+ for td in reversed(trading_days):
+ if td <= current_date:
+ current_trading_day = td
+ break
+
+ if not current_trading_day:
+ current_trading_day = current_date
+
+ # 计算时间范围:每个交易日从上一交易日15:00到当天15:00
+ # 对于 days=1(当前交易日),范围是:上一交易日15:00 到 当前交易日15:00
+
+ # 找到往前 days 个交易日
+ try:
+ current_idx = trading_days.index(current_trading_day)
+ start_trading_day_idx = max(0, current_idx - days + 1)
+ start_trading_day = trading_days[start_trading_day_idx]
+
+ # 找 start_trading_day 的前一个交易日
+ if start_trading_day_idx > 0:
+ prev_start_day = trading_days[start_trading_day_idx - 1]
+ else:
+ prev_start_day = start_trading_day - timedelta(days=1)
+ except ValueError:
+ # current_trading_day 不在列表中,使用简单计算
+ start_trading_day = current_trading_day - timedelta(days=days)
+ prev_start_day = start_trading_day - timedelta(days=1)
+
+ # 查询时间范围:从 prev_start_day 15:00 到 current_trading_day 15:00
+ start_datetime = datetime.combine(prev_start_day, dt_time(15, 0))
+ end_datetime = datetime.combine(current_trading_day, dt_time(15, 0))
+
+ # 如果当前时间还没到15:00,结束时间用当前时间
+ if is_trading and not is_after_close:
+ end_datetime = base_date if isinstance(base_date, datetime) else datetime.combine(current_date, dt_time(23, 59))
# 查询事件数据
events_query = db.session.query(Event).filter(
- Event.created_at >= start_date,
- Event.created_at <= end_date + timedelta(days=1),
+ Event.created_at >= start_datetime,
+ Event.created_at <= end_datetime,
Event.status == 'active'
).order_by(Event.created_at.desc()).all()
diff --git a/src/views/Community/components/EventDailyStats.js b/src/views/Community/components/EventDailyStats.js
index 48137010..7624ed05 100644
--- a/src/views/Community/components/EventDailyStats.js
+++ b/src/views/Community/components/EventDailyStats.js
@@ -24,6 +24,17 @@ import {
} from '@ant-design/icons';
import { getApiBase } from '@utils/apiConfig';
+/**
+ * 生成事件详情页 URL
+ * @param {number} eventId - 事件ID
+ * @returns {string} 事件详情页 URL
+ */
+const getEventDetailUrl = (eventId) => {
+ // 使用 base64 编码 ID,格式:ev-{id} -> base64
+ const encodedId = btoa(`ev-${eventId}`);
+ return `/event-detail?id=${encodedId}`;
+};
+
/**
* 格式化涨跌幅
*/
@@ -99,48 +110,61 @@ const CompactStatCard = ({ label, value, icon, color = '#FFD700', subText, progr
);
/**
- * TOP事件列表项
+ * TOP事件列表项 - 支持点击跳转
*/
-const TopEventItem = ({ event, rank }) => (
-
- {
+ const handleClick = () => {
+ if (event.id) {
+ // 在新标签页打开事件详情
+ window.open(getEventDetailUrl(event.id), '_blank');
+ }
+ };
+
+ return (
+ e.key === 'Enter' && handleClick()}
>
- {rank}
-
-
+
+ {rank}
+
+
+
+ {event.title}
+
+
- {event.title}
+ {formatChg(event.maxChg)}
-
-
- {formatChg(event.maxChg)}
-
-
-);
+
+ );
+};
const EventDailyStats = () => {
const [loading, setLoading] = useState(true);
@@ -215,9 +239,7 @@ const EventDailyStats = () => {
);
}
- const { summary, topPerformers = [], dailyStats = [] } = stats;
- // 获取当日TOP事件
- const todayTopEvents = dailyStats[0]?.topEvents || topPerformers.slice(0, 3);
+ const { summary, topPerformers = [] } = stats;
return (
{
{/* 分割线 */}
- {/* TOP表现事件 */}
-
+ {/* TOP表现事件 - 显示 TOP10 */}
+
今日 TOP 表现
+
+ (点击查看详情)
+
-
- {todayTopEvents.slice(0, 3).map((event, idx) => (
+
+ {topPerformers.slice(0, 10).map((event, idx) => (
))}
- {todayTopEvents.length === 0 && (
+ {topPerformers.length === 0 && (
暂无数据