## 新增功能 - 文件管理模块:分类树 + 文件上传/下载/删除 - 文件上传支持拖拽(Dragger)+ 手动上传(customRequest 模式) ## 页面布局统一(参照评测执行页) - 仪表盘/评测对象/评测场景/评测报告 全部改为全高 flex 布局 - 统一内联页头样式(h2 + 竖线分隔 + 描述) - 表格撑满高度、overflow 处理 - 每页添加刷新按钮 ## Bug 修复 - 分类树操作按钮 hover 不可见(CSS 规则缺失) - 文件上传失败(multipart boundary 缺失) - LLM API 响应 content blocks 数组格式支持(_extract_content_from_api_response) - response_time_max_ms 被静默忽略(隐式规则传空 params) - 空 messages 导致 IndexError 崩溃 - poll_reply 异常中止整个 run(缺 try/catch) - engine finally 未关闭 session - 3 个页面 UTC 时间戳解析偏差 8 小时 ## 后端 - EvalEngine: poll_reply 异常保护、空 dialog 保护、session 关闭 - LLM API 响应解析支持 content-block-array 格式 - 隐式 response_time 规则正确传递 max_ms 参数 ## 前端 - api.ts: 移除手动 Content-Type(让浏览器自动添加 boundary) - Files.tsx: customRequest 替代 beforeUpload、布局优化 - index.css: 分类树 hover 规则 - Targets/Scenarios/Home/Reports: 全高布局改造 - 3 个页面时间戳改用 formatDateTime()(修复 UTC 偏差) Co-Authored-By: Claude <noreply@anthropic.com>
196 lines
7.3 KiB
Markdown
196 lines
7.3 KiB
Markdown
# AgentEvalTool 前端开发日志 — 评测执行页改版
|
||
|
||
**日期**: 2026-07-15
|
||
**基线版本**: v0.2.0-dev
|
||
**状态**: 已部署至 t480 开发线
|
||
**作者**: AgentEval Team
|
||
|
||
---
|
||
|
||
## 一、背景
|
||
|
||
本次开发在 v0.2.0-dev 基础上,对评测执行页(Runs)进行全面 UI 改版,同时修复了若干历史遗留的基础 Bug。
|
||
|
||
---
|
||
|
||
## 二、关键 Bug 修复
|
||
|
||
### 2.1 `index.css` 从未被引入(历史遗留)
|
||
|
||
**症状**: 所有全局 CSS(动画、hover、布局覆盖规则)完全无效,但无报错提示。
|
||
|
||
**根因**: `main.tsx` 缺少 `import './index.css'`,Vite 不会自动包含未被引用的 CSS 文件,导致该文件从项目创建以来就从未生效。
|
||
|
||
**修复**: 在 `main.tsx` 顶部添加:
|
||
```tsx
|
||
import './index.css'
|
||
```
|
||
|
||
**影响**: 修复后构建产物首次出现独立 `.css` 文件(`dist/assets/index-*.css`),全局 CSS 规则一次性全部生效。
|
||
|
||
---
|
||
|
||
### 2.2 UTC 时间戳显示偏差 8 小时
|
||
|
||
**症状**: 评测记录时间比实际时间早 8 小时(如显示 16:40 实为次日 00:40 北京时间)。
|
||
|
||
**根因(三层叠加)**:
|
||
```
|
||
utc_now() → datetime(UTC)
|
||
↓ SQLite 不保存时区
|
||
"2026-07-14T16:40:00"(无 Z 后缀)
|
||
↓ ECMAScript 规范:无时区字符串按本地时间解析
|
||
new Date("2026-07-14T16:40:00") → 北京时间 16:40(比 UTC 多 8 小时)
|
||
```
|
||
|
||
**修复**: 在 `frontend/web/src/utils/date.ts` 添加 `toDate()` 工具函数:
|
||
```ts
|
||
export function toDate(iso: string): Date {
|
||
if (iso.endsWith('Z') || /[+-]\d{2}:\d{2}$/.test(iso)) return new Date(iso)
|
||
return new Date(iso + 'Z') // 追加 Z,强制按 UTC 解析
|
||
}
|
||
```
|
||
|
||
所有解析后端时间戳的地方统一使用 `toDate()`,不再直接 `new Date(str)`。
|
||
|
||
**注意**: 此问题根本解决方式是后端序列化时附带时区(如 `datetime.isoformat()` → `+00:00`),前端修复为应急兜底。
|
||
|
||
---
|
||
|
||
### 2.3 时间过滤器与显示时区不一致
|
||
|
||
**症状**: 今天发起的记录显示为正确的北京时间,但选择「当天」时过滤器找不到这些记录。
|
||
|
||
**根因**: `shortDateTime()` 已使用 `toDate()`(UTC 解析正确),但 `RunList` 过滤器仍用 `new Date(r.started_at)` 按本地时间解析,两者时间基准不一致,差了 8 小时导致过滤失败。
|
||
|
||
**修复**: 过滤器改用 `toDate()` 统一时间基准:
|
||
```ts
|
||
const t = r.started_at ? toDate(r.started_at).getTime() : null
|
||
```
|
||
|
||
---
|
||
|
||
## 三、评测执行页改版详情
|
||
|
||
### 3.1 全局布局修复
|
||
|
||
| 问题 | 修复方案 |
|
||
|---|---|
|
||
| 页面产生外层滚动条 | `App.tsx` tab 容器改为 `height: 100%, boxSizing: border-box`,消除 `minHeight + padding` 叠加导致的溢出 |
|
||
| 页面顶部出现空隙 | `html, body { margin: 0; padding: 0 }` + 覆盖 Ant Design `editable-card` Tabs 默认 `paddingTop` |
|
||
| Grid 子元素高度失效 | 增加 `gridTemplateRows: '1fr'`,显式让单行撑满 Grid 高度 |
|
||
| 魔法数字 `calc(100vh - 152px)` | 用 `PageWrapper fullHeight` + flex 链代替,彻底去除硬编码数字 |
|
||
| 内容区未贴边 | `Layout.Content` 及所有容器 padding 归零,内容贴合浏览器边缘 |
|
||
|
||
### 3.2 左侧面板 — 启动区
|
||
|
||
- **两行布局**: 第一行「评测对象」Select 全宽;第二行「评测场景 + 启动」并排
|
||
- **Select 增强**: `showSearch`(输入过滤)+ `allowClear`(清除按钮)
|
||
- **背景色**: 区域改为 `colors.bgSubtle`(`#fafafa`)浅底色,与列表区视觉分隔
|
||
|
||
### 3.3 左侧面板 — 筛选区
|
||
|
||
**三行布局:**
|
||
```
|
||
Row 1: [搜索框 full-width]
|
||
Row 2: [全部 进行中 成功 失败] [当天][1天][7天][30天] [N条]
|
||
```
|
||
|
||
**时间快捷标签**(替代 DatePicker):
|
||
- 当天:自然日 00:00 ~ 23:59(本地时间)
|
||
- 1天:昨天 + 今天
|
||
- 7天:最近 7 天含今天
|
||
- 30天:最近 30 天含今天
|
||
- 默认选中「当天」;再次点击取消(回到全部时间)
|
||
|
||
**状态分段**: 默认「全部」,选中态蓝底白字(ConfigProvider Segmented token)
|
||
|
||
**时间标签颜色**: 激活态蓝色实心背景 + 白字;未激活态深灰边框 + 深色文字
|
||
|
||
### 3.4 左侧面板 — 列表
|
||
|
||
| 项目 | 改动 |
|
||
|---|---|
|
||
| 行结构 | 三行固定(名称/元信息/进度条),等高不抖动 |
|
||
| 进度条 | pending/running 显示蓝色动态进度(来自 liveProgress);completed 显示通过率色阶 |
|
||
| 分页 | 每页 10 条,底部固定分页栏(始终占位,布局稳定) |
|
||
| 排序 | 去掉错误的 `.reverse()`,API 已按 `started_at DESC` 返回 |
|
||
| hover | 去掉 `onMouseEnter/Leave` 直接操作 DOM,改为 CSS `.run-row:hover` |
|
||
|
||
### 3.5 右侧面板 — Tab 滚动
|
||
|
||
**问题**: 三个 Tab(实时对话、规则总览、用例明细)内容区无法独立滚动。
|
||
|
||
**根因**: Ant Design v5 使用 CSS-in-JS(emotion)在运行时注入样式,覆盖了静态 CSS 文件中的 `flex`/`height` 规则,导致 Tab 内容区高度链断裂。
|
||
|
||
**最终方案(导航与内容分离)**:
|
||
```
|
||
Tabs(.nav-only-tabs):只渲染导航头,内容区 display: none
|
||
↓
|
||
三个内容 div(直接 flex 子元素):
|
||
flex: 1, min-height: 0, overflowY: auto
|
||
→ 高度由 flex 算法直接确定,不经过 Ant Design 内部 DOM
|
||
```
|
||
|
||
```css
|
||
.ant-tabs.nav-only-tabs .ant-tabs-content-holder {
|
||
display: none !important;
|
||
}
|
||
```
|
||
|
||
三个 Tab 的滚动各自独立,互不干扰。
|
||
|
||
---
|
||
|
||
## 四、其他优化
|
||
|
||
| 项目 | 内容 |
|
||
|---|---|
|
||
| 代码去重 | 提取 `startRun()` 函数,消除 `handleStart` 与 `onRerun` 重复逻辑 |
|
||
| 死代码清理 | 删除 `sessionReducer` 中从未被 dispatch 的 `SET_RUN` action |
|
||
| 工具函数复用 | `RunList` 改用 `shortDateTime` / `elapsedStr`,删除本地重复的 `formatStart` / `durationStr` |
|
||
| 类型安全 | `run.summary as any` 改为 `Record<string, unknown>` 类型收窄 |
|
||
| Bundle 瘦身 | 用时间标签替代 DatePicker,vendor chunk 缩小约 107KB |
|
||
| CSS 组件化 | Segmented 选中态、Run list hover 统一移入 ConfigProvider token / CSS 类,不再散落在组件 inline style |
|
||
|
||
---
|
||
|
||
## 五、t480 部署记录
|
||
|
||
**部署前环境补全**(首次排查发现):
|
||
|
||
`.env` 只有 1 个键(`AGENTEVAL_ALLOWED_ORIGINS`),缺失以下配置:
|
||
|
||
```bash
|
||
AGENTEVAL_API_KEY=
|
||
AGENTEVAL_OPENCLAW_UPSTREAM=http://openclaw-eval:18789
|
||
AGENTEVAL_OPENCLAW_WS_UPSTREAM=ws://openclaw-eval:18789
|
||
AGENTEVAL_OPENCLAW_PROXY_USER=agenteval
|
||
AGENTEVAL_OPENCLAW_AUTH_TOKEN=change-me-in-production
|
||
```
|
||
|
||
已通过 SSH 补全,OpenClaw 代理功能恢复正常。
|
||
|
||
---
|
||
|
||
## 六、遗留问题
|
||
|
||
| 问题 | 状态 | 说明 |
|
||
|---|---|---|
|
||
| case-001 无发送气泡 | 待查 | 只有智能体回复,无用户发送内容;需确认 DB 中 `turn.sent_message` 字段内容 |
|
||
| UTC 时间后缀 | 待优化 | 当前前端追加 `Z` 兜底;根本修复需后端序列化附带时区标记 |
|
||
|
||
---
|
||
|
||
## 七、文件变更清单
|
||
|
||
**前端**
|
||
- `src/main.tsx` — 添加 `import './index.css'`
|
||
- `src/index.css` — html/body 重置、nav-only-tabs、TabBar padding 覆盖、Segmented 样式
|
||
- `src/App.tsx` — 布局修复(overflow、padding),Segmented token
|
||
- `src/components/PageWrapper.tsx` — 新增 `fullHeight` prop
|
||
- `src/pages/Runs.tsx` — 完整重构:布局、启动区、内联头部、Tab 分离
|
||
- `src/components/RunList.tsx` — 筛选区三行布局、时间标签、toDate 对齐、分页
|
||
- `src/utils/date.ts` — 新增 `toDate()`(export),修复时区
|
||
- `src/hooks/sessionReducer.ts` — 删除 `SET_RUN` 死代码
|