1. 页面概览
审计日志页是 AIP 管理后台的审计查询入口,路由 /admin/audit,仅管理员可访问。它读取平台 audit_log 表中的审计事件,按用户、事件类型、时间范围与条数筛选查询,并可逐条展开查看 action_details 详情 JSON。登录、NLQ 查询、AI 决策、数据源操作等关键动作都会落库一条审计记录,本页为管理员与安全审计人员提供"谁在何时做了什么"的取证能力。页面为轻量查询形态:顶部刷新按钮 + 筛选条 + 日志表格 + 上一页/下一页分页,无导出。
2. 访问入口
2.1 路由与菜单
path /admin/audit、name AdminAudit、title 审计日志;挂载在父路由 /admin(AdminLayout)下,侧边栏菜单项「审计日志」。源码 action/web/src/views/AuditLogPage.vue,注册于 action/web/src/router/index.js。
2.2 认证与权限
父路由 meta 为 requiresAuth: true, requiresAdmin: true,非管理员(localStorage.aip_is_admin !== '1')被前端守卫重定向到智能查询页。请求经 aipClient.js 附带 Authorization: Bearer <aip_token>,后端 401 清 Token 跳登录,非管理员请求 admin 组接口返回 403。
2.3 端口与 API 前缀
AIP 后端 18080,前缀 /aip-api(baseURL /aip-api/v1,Vite 代理重写为 /api/v1)。
3. 界面布局
审计日志 [刷新]
[操作结果提示 alert(可关闭)]
筛选条:用户ID | 事件类型(逗号分隔,可下拉选已出现类型/可手填) | 开始/结束时间 | 条数(20/50/100)
[查询] [重置]
日志列表:ID | 时间 | 用户ID | 事件类型 | 结果 | 详情(展开/收起)
展开行 = action_details 格式化 JSON
分页:[上一页] 第 P 页 · 每页 N 条 · 本页 M 条 [下一页]
- 操作结果提示:单例 alert,查询成功(alert-success)/失败(alert-error)经
showAlert写入,「关闭」清空。 - 筛选条:五个过滤输入 +「查询」「重置」,重置后按默认条件重新拉取。事件类型输入框挂
<datalist>,候选聚合自当前已加载日志中出现过的event_type(仅快捷录入、不完整,仍可手填)。 - 日志列表:加载中显示"加载中...",空结果显示"暂无日志。"。
4. 交互元素
| 控件 | 位置 | 含义与作用 |
|---|---|---|
| 刷新按钮 | 页面头部 | 按当前筛选条件重新拉取日志 |
| 用户 ID 输入框 | 筛选条 | 按用户精确过滤,如 1;空则不过滤 |
| 事件类型输入框(datalist 候选) | 筛选条 | 逗号分隔列表,如 LOGIN,QUERY;空则不过滤。带 <datalist> 下拉候选,候选聚合自当前已加载日志中出现过的 event_type(只增不减),不完整、仍可直接手填(后端无类型枚举端点) |
| 开始/结束时间 | 筛选条 | datetime-local 选择器,前端转 RFC3339(补 :00+08:00) |
| 条数下拉框 | 筛选条 | 单次加载条数 20/50/100,默认 20 |
| 查询 / 重置按钮 | 筛选条 | 查询按当前条件拉取;重置清空过滤项后重拉 |
| 展开 / 收起按钮 | 表格每行 | 展示该行 action_details 的格式化 JSON |
| 结果徽标 | 表格列 | result 为 SUCCESS 绿色(status-on),其余红色(status-off),空值灰色 |
5. 后端关联
5.1 端点表
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /audit/logs | 查询审计日志,query 支持 limit/offset/user_id/event_type(逗号分隔)/start_time/end_time(RFC3339) |
5.2 请求与响应
成功返回 {"logs": [...]},每条含 id、timestamp、user_id、event_type、action_details、result、ref_type、ref_id、step_type。后端 limit 默认 50、offset 默认 0,时间解析失败时忽略。
5.3 关键机制
- 审计写入为异步 worker 消费队列落库,查询读热表;
action_details为 JSON 文本,前端JSON.parse后格式化,解析失败原样展示。时间经toRFC3339统一补秒与+08:00时区后缀。 - 事件类型候选:后端无事件类型枚举/字典端点——
handleAuditLogs只把event_type当作过滤参数(逗号分隔 →WHERE),响应体只有{"logs":[...]},不返回类型清单(handlers.go:487-528)。故前端候选聚合自已加载日志(event_type并集,只增不减),并在控件旁常驻如实标注「候选来自当前已加载日志,不完整,可手填」。 - 后端位置:路由注册于
action/products/aip/server/server.go(admin 组),处理函数handleAuditLogs位于action/products/aip/server/handlers.go。
6. 权限与安全
- 认证:JWT Bearer Token(
aip_token),401 清 Token 跳/login。 - 双重要求:前端
requiresAdmin守卫 + 后端authMiddleware + adminMiddleware双中间件,非管理员 403。 - 写操作防护:本页纯只读查询,无写接口;详情 JSON 只读展示不可修改。
7. 常见问题与排错
问题 1:提示「加载审计日志失败:...」
- 现象:列表不出数据,顶部红色 alert 报错。
- 原因:Token 失效(401)、后端未启动、或 Vite 代理未指向 18080。
- 处理:看 Network 中
/aip-api/v1/audit/logs状态;401 重新登录,404 查代理,并确认 AIP 进程存活。
问题 2:非管理员访问被重定向到智能查询页
- 现象:直接访问
/admin/audit被跳Chat页。 - 原因:守卫检测
aip_is_admin不为1。 - 处理:用管理员账号重新登录(登录后写入
aip_is_admin=1)再访问。
问题 3:按事件类型过滤查不到结果
- 现象:输入
LOGIN,QUERY查询为空。 - 原因:事件类型为精确匹配,大小写敏感,需与库中
event_type完全一致(如平台实际写入的是USER_LOGIN,见platform/auth/auth_service.go:129等)。 - 处理:输入框已挂
<datalist>候选,展开下拉可直接选本次已加载日志中出现过的类型(候选不完整);或先查全量,从结果复制准确类型字符串再过滤。
问题 4:时间过滤与实际不符
- 现象:选择时间段后结果包含范围外记录。
- 原因:
datetime-local无秒级输入,前端补:00;浏览器时区非东八区时+08:00会有偏差。 - 处理:确认系统时区为东八区,或直接核库中
timestamp文本。
8. 已知缺陷与边界
| 项 | 说明 |
|---|---|
| 无导出 | 与 Foundry 审计页不同,本页不提供 CSV/JSON 导出 |
| 徽标二值化 | 非 SUCCESS 一律红色,不区分 FAILURE/DENIED 等中间态 |
| 事件类型候选不完整(非独立枚举端点) | 事件类型输入框已挂 <datalist> 候选,但后端无事件类型枚举/字典端点(handlers.go:487-528 仅把 event_type 当过滤参数、响应只含 logs),候选只能聚合自已加载日志中出现过的取值(只增不减),仍支持手填;要拿到全量类型需后端新增枚举端点 |
| 分页无 total | 响应体只有 {"logs":[...]} 无 total(handlers.go:527),下一页按「本页行数 == 每页条数」满页启发式判断,末页恰满时会多一次空翻(已自动回退一页) |
注:offset 写死 0 无法翻页(每次固定取前 limit 条,大批量需缩小过滤范围)已于 2026-09-06 修复(上一页/下一页 + 页码指示)。