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