diff --git a/backend/app/core/middleware.py b/backend/app/core/middleware.py index 7d2a1bd..a987219 100644 --- a/backend/app/core/middleware.py +++ b/backend/app/core/middleware.py @@ -14,23 +14,23 @@ class TerminalCheckMiddleware(BaseHTTPMiddleware): # 2. 检查时间戳 (防重放/时钟同步) # 优先从Header获取,如果没有则尝试从Query Parameter获取 - # client_time_str = request.headers.get("time") or request.query_params.get("time") + client_time_str = request.headers.get("time") or request.query_params.get("time") - # if client_time_str: - # try: - # client_time = int(client_time_str) - # server_time = int(time.time() * 1000) + if client_time_str: + try: + client_time = int(client_time_str) + server_time = int(time.time() * 1000) - # # 允许 10 分钟的误差 (10 * 60 * 1000 = 600000 ms) - # # 考虑到网络延迟和设备时间未校准,设置宽松一点 - # if abs(server_time - client_time) > 600000: - # return create_api_response( - # code="400", - # message="设备时间与服务器时间差距过大,请校准时间" - # ) - # except ValueError: - # # 时间格式错误,暂时忽略或返回错误 - # pass + # 允许 10 分钟的误差 (10 * 60 * 1000 = 600000 ms) + # 考虑到网络延迟和设备时间未校准,设置宽松一点 + if abs(server_time - client_time) > 600000: + return create_api_response( + code="400", + message="设备时间与服务器时间差距过大,请校准时间" + ) + except ValueError: + # 时间格式错误,暂时忽略或返回错误 + pass # 3. 提取其他设备信息 device_type = request.headers.get("deviceType", "UNKNOWN") diff --git a/frontend/src/pages/AdminDashboard.jsx b/frontend/src/pages/AdminDashboard.jsx index a41b3da..131953a 100644 --- a/frontend/src/pages/AdminDashboard.jsx +++ b/frontend/src/pages/AdminDashboard.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { LogOut, User, Users, Activity, Server, HardDrive, Cpu, MemoryStick, RefreshCw, UserX, ChevronDown, KeyRound, Shield, BookText, Waves, UserCog, Search } from 'lucide-react'; +import { LogOut, User, Users, Activity, Server, HardDrive, Cpu, MemoryStick, RefreshCw, UserX, ChevronDown, KeyRound, Shield, BookText, Waves, UserCog, Search, FileJson } from 'lucide-react'; import apiClient from '../utils/apiClient'; import { buildApiUrl, API_ENDPOINTS } from '../config/api'; import Dropdown from '../components/Dropdown'; @@ -264,6 +264,28 @@ const AdminDashboard = ({ user, onLogout }) => { } }; + const handleDownloadTranscript = async (meetingId) => { + try { + const response = await apiClient.get(buildApiUrl(`/api/meetings/${meetingId}/transcript`)); + if (response.code === '200') { + const dataStr = JSON.stringify(response.data, null, 2); + const blob = new Blob([dataStr], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = `transcript_${meetingId}.json`; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } else { + showToast('获取转录数据失败', 'error'); + } + } catch (err) { + console.error('Download transcript error:', err); + showToast('下载失败', 'error'); + } + }; + if (loading && !stats) { return ; } @@ -690,6 +712,32 @@ const AdminDashboard = ({ user, onLogout }) => { )} + + {/* 转录结果下载 */} +
+ 转录结果: +
+ +
+
) : (
无法加载数据
diff --git a/frontend/src/pages/MeetingDetails.css b/frontend/src/pages/MeetingDetails.css index 428f8b0..bd68da2 100644 --- a/frontend/src/pages/MeetingDetails.css +++ b/frontend/src/pages/MeetingDetails.css @@ -537,6 +537,7 @@ border-radius: 12px; padding: 1.5rem; backdrop-filter: blur(10px); + min-height: 200px; /* Prevent layout shift */ } /* 转录状态显示样式 - 一行显示 */