fix(ui): 日期维度改用视频录制时间 - 前端事件时间轴/统计/关注事件与后端 db_layer 统一按 event_start_time(文件名解析) 分组排序,空值回退 processed_at;修复全量重分析导致处理时间(8/21)把 8/15-8/20 视频全堆同一天、与文件名对不上的问题

This commit is contained in:
ericwyuan
2026-08-21 15:00:41 +08:00
parent 0d73c23bd1
commit da7631976d
2 changed files with 46 additions and 35 deletions

View File

@@ -379,19 +379,22 @@ if page == "🕒 事件时间轴":
conn = get_db_conn()
try:
cursor = conn.cursor()
# 日期维度统一用视频实际录制时间 event_start_time文件名解析
# 为空时回退 processed_at分析时间避免"处理时间=8/21"把旧视频全堆同一天
_DATE_EXPR = "COALESCE(NULLIF(event_start_time,''), processed_at)"
if date_str:
cursor.execute(
"SELECT COUNT(*) v FROM sync_videos WHERE status='done' AND processed_at LIKE %s",
f"SELECT COUNT(*) v FROM sync_videos WHERE status='done' AND {_DATE_EXPR} LIKE %s",
(f'{date_str}%',))
v = cursor.fetchone().get('v', 0)
cursor.execute(
"SELECT COUNT(*) e FROM sync_events se JOIN sync_videos sv ON se.video_id=sv.id WHERE sv.processed_at LIKE %s",
f"SELECT COUNT(*) e FROM sync_events se JOIN sync_videos sv ON se.video_id=sv.id WHERE {_DATE_EXPR} LIKE %s",
(f'{date_str}%',))
e = cursor.fetchone().get('e', 0)
cursor.execute(
"""SELECT COALESCE(SUM(se.is_attention_event),0) AS att
f"""SELECT COALESCE(SUM(se.is_attention_event),0) AS att
FROM sync_events se JOIN sync_videos sv ON se.video_id=sv.id
WHERE sv.processed_at LIKE %s""", (f'{date_str}%',))
WHERE {_DATE_EXPR} LIKE %s""", (f'{date_str}%',))
att = cursor.fetchone().get('att', 0)
else:
cursor.execute("SELECT COUNT(*) v FROM sync_videos WHERE status='done'")
@@ -435,22 +438,22 @@ if page == "🕒 事件时间轴":
cursor = conn.cursor()
if date_str:
cursor.execute(
"""SELECT id, filename, camera_name, event_start_time, summary_json,
f"""SELECT id, filename, camera_name, event_start_time, summary_json,
compute_provider, processed_at,
(SELECT COUNT(*) FROM sync_events se WHERE se.video_id=sync_videos.id) AS event_count
FROM sync_videos
WHERE status='done' AND processed_at LIKE %s
ORDER BY COALESCE(processed_at, updated_at, created_at) DESC
WHERE status='done' AND {_DATE_EXPR} LIKE %s
ORDER BY {_DATE_EXPR} DESC
LIMIT %s OFFSET %s""",
(f'{date_str}%', page_size, offset))
else:
cursor.execute(
"""SELECT id, filename, camera_name, event_start_time, summary_json,
f"""SELECT id, filename, camera_name, event_start_time, summary_json,
compute_provider, processed_at,
(SELECT COUNT(*) FROM sync_events se WHERE se.video_id=sync_videos.id) AS event_count
FROM sync_videos
WHERE status='done'
ORDER BY COALESCE(processed_at, updated_at, created_at) DESC
ORDER BY {_DATE_EXPR} DESC
LIMIT %s OFFSET %s""",
(page_size, offset))
videos = cursor.fetchall()
@@ -479,10 +482,10 @@ if page == "🕒 事件时间轴":
f'margin-bottom:10px;">视频会话 · {len(videos)} 条</div>',
unsafe_allow_html=True)
for vid in videos:
proc = vid.get('processed_at')
ptime = parse_ts(proc)
time_label = ptime.strftime('%m-%d %H:%M') if ptime else '--:--'
date_label = ptime.strftime('%Y-%m-%d') if ptime else ''
# 日期标签/时间用视频实际录制时间event_start_time为空回退处理时间
ev_time = parse_ts(vid.get('event_start_time')) or parse_ts(vid.get('processed_at'))
time_label = ev_time.strftime('%m-%d %H:%M') if ev_time else '--:--'
date_label = ev_time.strftime('%Y-%m-%d') if ev_time else ''
summary = (vid.get('summary_json') or '').strip()
summary_short = summary if len(summary) <= 28 else summary[:28] + ''
if not summary_short:
@@ -515,13 +518,15 @@ if page == "🕒 事件时间轴":
with col_detail:
vid = next(v for v in videos if v['id'] == selected_id)
proc = parse_ts(vid.get('processed_at'))
start = parse_ts(vid.get('event_start_time'))
proc = parse_ts(vid.get('processed_at'))
# 主时间 = 录制时间event_start_time回退分析时间processed_at
main_t = start or proc
range_str = ''
if proc:
range_str = proc.strftime('%Y-%m-%d %H:%M:%S')
if start:
range_str += f"起始 {start.strftime('%H:%M:%S')}"
if main_t:
range_str = main_t.strftime('%Y-%m-%d %H:%M:%S')
if start and proc and (proc - start).total_seconds() > 60:
range_str += f"分析于 {proc.strftime('%m-%d %H:%M')}"
provider = vid.get('compute_provider') or ''
model_badges = ''
@@ -899,17 +904,18 @@ elif page == "📈 统计图表":
st.markdown('<div style="font-size:15px;font-weight:700;color:#f1f5f9;'
'margin:22px 0 14px 0;">关注事件统计</div>', unsafe_allow_html=True)
cursor.execute(
"""SELECT v.processed_at, e.person_list_json
"""SELECT COALESCE(NULLIF(v.event_start_time,''), v.processed_at) AS ev_date,
e.person_list_json
FROM sync_events e JOIN sync_videos v ON e.video_id=v.id
WHERE e.is_attention_event = 1
ORDER BY v.processed_at DESC""")
ORDER BY ev_date DESC""")
attention = cursor.fetchall()
if attention:
import pandas as pd
rows = []
for a in attention:
persons = parse_persons(a['person_list_json'])
ptime = parse_ts(a['processed_at'])
ptime = parse_ts(a['ev_date'])
rows.append({
"日期": ptime.strftime('%Y-%m-%d') if ptime else '?',
"人物": ','.join(sorted(persons)) or '无人',