1. 页面概览
情报报告页(/gotham/reports)是 LightGotham 的书面分析产出中心:支持手动创建、从数据生成、从模板创建三类建报方式;报告按 draft → published → archived 流转,可查看 HTML 渲染、导出 PDF/DOCX;内置「报告工作台」(TAD-10)提供富文本编辑、嵌入图/地图/时间轴快照、版本管理。一句话总结:本页把情报结论沉淀为可编辑、可导出、可发布归档的正式报告。
2. 访问入口
2.1 路由与菜单
path /gotham/reports、name GothamReports、title Gotham 情报报告,子路由挂在父路由 /gotham(GothamLayout)下,侧边栏菜单项「情报报告」。源码 action/web/src/views/GothamReportsPage.vue。
2.2 认证与权限
子路由 meta requiresAuth: true;请求经 gothamClient.js 附带 aip_token,401 用 gotham_refresh_token 换新重放。
2.3 端口与 API 前缀
Gotham 后端 18083,前缀 /gotham-api(baseURL /gotham-api/v1,Vite 代理重写为 /api/v1)。
3. 界面布局
Gotham 情报报告 [刷新]
[操作结果提示 alert(可关闭)]
创建报告卡 | 从数据生成卡 | 从模板创建卡 ← 三列并列
报告列表(ID/标题/类型/状态/版本/作者/更新时间/操作)
[报告 HTML 查看模态] [报告工作台模态]
- 顶部:标题 + 「刷新」重拉报告与模板。
- 创建区:三卡并列(创建报告 / 从数据生成 / 从模板创建)。
- 报告列表:逐行操作;空态「暂无报告,请创建或生成。」。
- 模态层:查看模态 iframe srcdoc 渲染 HTML;工作台模态含三标签页。
4. 交互元素
| 控件 | 位置 | 含义与作用 |
|---|---|---|
| 输入「标题 *」「概要」+ 类型下拉 | 创建报告卡 | 标题必填;类型 analysis/incident/entity/general |
| 按钮「创建」 | 创建报告卡 | POST /reports 建草稿并刷新列表 |
| 输入「实体 rid」+ 按钮「生成报告」 | 从数据生成卡 | 填实体 rid(如 graph:person:zhy),POST /reports/generate 用 entity 节生成 |
| 下拉模板 + 按钮「从模板创建」 | 从模板创建卡 | POST /reports/from-template,可按需附实体 rid |
| 行内「查看/工作台/复制/PDF/DOCX」 | 报告列表 | 查看=拉 HTML 渲染;工作台=打开编辑模态;PDF/DOCX=blob 下载 |
| 按钮「发布」「归档」 | 报告列表 | 按状态显隐:非 published/archived 显示「发布」,published 显示「归档」 |
| 标签页「富文本编辑/嵌入对象/版本管理」 | 工作台 | 三个子面板;工具栏提供 B/I、H1/H2/H3、无序列表、有序列表、撤销/重做 |
| 按钮「保存内容」 | 工作台·富文本 | 把编辑器文档双向序列化为后端结构化块 PUT /reports/:id(标题→heading、段落→paragraph、有序/无序列表→list),版本 +1 |
| 非编辑块只读区 | 工作台·富文本 | table/kv/image/embedded_object 无对应 Tiptap 节点,在编辑器下方只读列出(类型 + 摘要),保存时原样追加到内容末尾(不静默丢数据) |
| 按钮「添加嵌入对象」「刷新全部快照」 | 工作台·嵌入对象 | 添加 graph/map/timeline 对象(查询参数 JSON,如 {"entity_id":"graph:person:zhy","depth":2});刷新重生成快照 |
| 按钮「恢复此版本」 | 工作台·版本管理 | POST /reports/:id/versions/:version/restore,回滚再 +1 版本 |
5. 后端关联
端点表(源码 action/products/gotham/server/server.go,处理器 handlers_reports.go):
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /reports | 报告列表 |
| POST | /reports | 创建草稿(title/report_type/summary/description) |
| PUT | /reports/:id | 更新标题/内容,保存后版本 +1 |
| POST | /reports/:id/publish、/archive | 状态流转 draft→published→archived |
| POST | /reports/generate | 按 sections(entity 节)生成 |
| GET | /reports/:id/html | 报告 HTML 文本(axios 带 JWT 拉取) |
| GET | /reports/:id/pdf、/docx | blob 导出下载 |
| GET | /reports/templates、POST /reports/from-template | 模板列表与从模板创建 |
| POST | /reports/:id/duplicate | 复制报告 |
| GET/POST | /reports/:id/objects、DELETE /reports/:id/objects/:object_id、POST /reports/:id/objects/refresh | 嵌入对象管理 |
| GET | /reports/:id/versions、POST /reports/:id/versions/:version/restore | 版本历史与回滚 |
- 状态机:
draft → published → archived。发布要求 draft、归档要求 published;列表按钮按状态显隐。 - 版本机制:每次保存(PUT)自动生成版本快照;恢复旧版本不是覆盖而是再产生新版本(确认框提示「回滚本身会再 +1 版本」)。
- 富文本双向序列化:Tiptap(StarterKit)编辑。保存走
tiptapToBlocks(editor.getJSON()):heading→{type:'heading',data:{text,level}}(level 限 1~3,越界按 1,与后端HeadingBlock/blockToHTML口径一致)、段落→{type:'paragraph',data:{text}}、无序/有序列表→{type:'list',data:{items:[...]}}(items 为字符串数组,对齐后端ListData,models.go:238-240)。回填走blocksToTiptap:heading/paragraph/list 还原为编辑器节点。后端块模型只有text字段、无行内富文本结构,加粗/斜体无法落库,页面已如实标注。 - 非编辑块保留:
table/kv/image/embedded_object后端白名单内但 Tiptap StarterKit 无对应节点,页面在编辑器下方只读列出(类型 + 摘要),保存时原样追加到content末尾(顺序会移到末尾,但内容不丢失)。后端写入期validateBlocks会逐块校验(service.go:111-119),非法块返回 400INVALID_REQUEST(错误文案带块序号)。 - 嵌入对象:以「类型 + 查询参数」登记,添加时生成快照,可「刷新全部快照」重生成。
6. 权限与安全
- 页面与全部接口均在受保护路由(JWT Bearer),无公开端点。
- 创建/生成/发布/归档等写操作经 ABAC PEP 写门(
server/abac_pep.go),deny 策略命中返回 403。 - 查看/导出 HTML 走 axios 携带 Authorization 头,URL 不暴露 token;导出由前端 blob URL 触发下载,服务端生成后即弃。
7. 常见问题与排错
- 查看模态提示「HTML 渲染失败」:点「查看」后模态内显示红色错误文本;原因是
GET /reports/:id/html失败(token 失效、后端未起、报告不存在);处理:看 Network 该请求状态,401 重新登录,404 确认报告存在。 - 导出的 PDF/DOCX 文件打不开或为空:下载成功但文件损坏或空白;原因是后端导出异常返回(空内容被当 blob 下载);处理:查后端日志
handleReportPDF/Docx,确认报告有内容并已保存。 - 保存内容后版本没有 +1:版本历史最新版号未变化;原因是
PUT /reports/:id失败(401/字段缺失);处理:看是否提示「保存失败」,确认已登录且报告存在,重试保存。 - 从模板创建时模板下拉为空:「选择模板…」无可选项;原因是
GET /reports/templates返回空(后端未预置);处理:查 Network 该接口返回,确认后端模板种子数据存在。
8. 已知缺陷与边界
| 项 | 说明 |
|---|---|
| 行内格式无法往返(后端契约边界) | 后端 paragraph/heading 载荷只有 text 字段,无行内富文本结构(reports/models.go:220-229),故加粗/斜体不会保存;页面工具栏旁已如实标注。标题与列表已可正确往返(改前为全部丢失) |
| 非编辑块顺序移至末尾 | table/kv/image/embedded_object 只读保留并在保存时追加到 content 末尾,原块相对顺序会变化(内容不丢);要保序需 Tiptap 侧实现对应节点 |
| 未知块类型 | 后端白名单外(validBlockTypes,service.go:80-88)的块不会被编辑器保留,保存时由后端 400 拒绝并给出块序号 |
| 版本恢复非覆盖 | 回滚生成新版本,历史版本全部保留 |
| 导出格式有限 | 仅 PDF/DOCX 两种;HTML 查看为整页 iframe 渲染,大报告加载慢 |
| 模板依赖后端 | 模板下拉空时「从模板创建」不可用 |
9. 2026-09-10 安全与行为修订
- 报告 HTML 预览 iframe 加 sandbox:整页 iframe 渲染加沙箱限制(禁脚本/禁表单提交等),报告内容不再拥有页面同源权限,防恶意内容逃逸。