# report_bioflow_dev3 —— P2-P5 前端编排闭环/报告/存档/面板(开发 agent A3) > 任务书:docs/team/brief_bioflow_dev3_p2p5.md > 工作分支:feature/bioflow-conversation-orchestration(保持,不切换) > 纪律:不 commit/push/部署;不碰生产服务(8090/8091/8098 从未探测);文案全部进 i18n/bioflow.js;类名遵循 UI_SPEC §8.7 ## 总览 | 小期 | 内容 | 新增文件 | 修改文件 | 自测 | |---|---|---|---|---| | P2 | 对话式编排闭环 | i18n/bioflow.js、utils/intent.js、api/bioflow.js、stores/bioflow.js、FlowPathCard/FlowFormCard/FlowFileCard/FlowProgressCard/FlowArchiveCard.vue | stores/chat.js(增量 sendBioflow+更新器)、AssistantMessage.vue(五类块分支)、Composer.vue(bioflow 分流) | 69+53+20+16+6=164 通过 | | P3 | 报告闭环 | (前端)report 登记/revise 动作;(后端增量)sdk/app/services/docgen/templates/bioflow_report.html/css + templating_bioflow.py(草稿,交 TL 审合入) | 无(DocPane 零改造目标达成) | 7 通过 + 后端离线渲染验证全过 | | P4 | 存档与复用 | FlowFormCard 复用模式(bioflow_reuse 块) | stores/bioflow.js(registerReport/revise/loadReusePrefill/runArchive)、chat.js(showReuseForm/archiveJob) | 6 通过 | | P5 | 生信任务面板 | BioJobsPane.vue、BioArchivePane.vue | BenchPanel.vue(生信 TAB 探活显隐)、AppShell.vue(移动端 tab 条) | 18+5=23 通过 | 自测口径:cd ui && npx vitest run(SSE 全部 mock,不依赖生产服务)——全量 373 passed(既有 173 + 生信新增 200),红线零改动(md5 与 git diff 双校验)。 ## 红线零改动声明 - ui/src/stores/modes.js(config/modes.js)、i18n/labels.js、stores/bench.js、api/qa.js、sse/parser.js、PipelineCard.vue:md5 与基线一致 + git diff 为空 - services/docgen 既有代码零改动:bioflow_report 模板为独立新文件(index.json 未动——docgen 团队 registry 用例断言 keys==7,不动注册表);templating_bioflow.py 为增量新模块;get_artifact_html 分支改动以草稿形式交 TL 审(sdk/ 既有代码零 diff;新增 4 个草稿文件 untracked 待 TL 审) - ui/src/intent.js(docgen 意图)在文件搬运时一度被生信版覆盖,已 git checkout 恢复,最终状态零改动 --- ## P2 对话式编排闭环(完成) ### 完成清单 | 模块 | 说明 | |---|---| | i18n/bioflow.js | 全部用户可见文案(含 BIOFLOW_TABS 定义、stageStatusText/jobStatusText 映射) | | utils/intent.js | 与 cases_bioflow_intent.md 冻结词典逐条一致(40 用例表同表双跑);复用方法名提取(REUSE_PHRASE 前 3-20 字符、去引导词/书名号);边界(≤1 纯空白 qa、>2000 截断、家族名语境词句尾规则) | | api/bioflow.js | 20 端点封装:health/catalog/chat/stream(SSE raw)/ask/jobs 全套/files(multipart XHR 进度+server_path 登记)/stages 控制/manifest/events(SSE raw)/archives 全套/report revise/reports register | | stores/bioflow.js | 探活(availability unknown/online/offline)、currentJob(applyEvent 逐帧+applySnapshot 整体替换)、connectJobEvents(EventSource 首帧快照+回放+终态不重连)、动作分发(confirm/rerun/skip/pause/resume/createJobFromPlan)、面板数据(jobs/archives/manifest/详情) | | stores/chat.js | sendBioflow 动作(仿 sendDocgen 独立分支,send/_runStream/sendDocgen 零改动)+ 8 个消息更新器(path/progress/snapshot/event/form/file/archiveSuggest/qa)+ bioflow 上传/路径登记动作 + retry 走生信路径 | | FlowPathCard | §8.1 逐字复刻(选中态 1.5px --pa-g-from + 8% 混色底、确认按钮渐变白字 12.5px/600、无选中禁用 .45)+ 确认视图(FR-BIO-004 逐阶段三要素)+ 复用徽章 + auto_filled 明示 + fallback 明示 | | FlowFormCard | §8.2 逐字复刻(label 96px 固定、input focus 渐变、来源标注 11px ink-subtle、继续按钮 7px 16px)+ 自动连续开关(mode-pill 同款)+ 数字/范围/choices 校验 + Enter 提交/Esc 恢复 + 提交中防重复 | | FlowFileCard | §8.3 逐字复刻(2px dashed hairline-strong、拖入态 45%/8% 混色、prog-track/prog-fill 进度+百分比 11px mono)+ 服务器路径输入行(pane-btn 同款)+ 上传中禁重复 + 失败可见可重试 | | FlowProgressCard | §8.4(复用 PipelineCard 全部令牌 done/running/waiting + 新增 failed --pa-error 底✕/skipped --pa-ink-subtle 底◌ + 日志尾区 code-bg mono 11px max-height 96px 滚动 + 三选一 pane-btn gap 8px + >10 阶段折叠分组默认展开运行中组) | | FlowArchiveCard | §8.5 逐字复刻(存档 --pa-gradient 12.5px/600、放弃 pane-btn、名称空禁用、存档中双禁用、存档失败可重试)+ 状态回复三要素展示 | | AssistantMessage | 五类块分支(bioflow_path/form/file/progress/archive + bioflow_qa 引用块);PipelineCard 零改动 | | Composer | routeBioflow 分流(bioflow/bioflow_qa 走 sendBioflow;词典不命中一律 qa 漏判安全);offline 探活关闭生信分流 | ### 自测结果 (SSE 用 mock): - intent.test.js:53 通过(40 词典用例表 + 边界/复用提取/语境词) - cards.test.js:69 通过(五卡片全状态 + UI 动作矩阵:点击/双击/悬停/键盘 Enter/Esc/拖入/拖放/离开/聚焦/失焦/禁用/加载中) - bioflow.store.test.js:20 通过 - chat.bioflow.test.js:16 通过(sendBioflow 全流程 SSE mock、错误帧、断线 disconnected、retry 同位置替换、busy 防护) - composer.bioflow.test.js:6 通过(分流/漏判安全/探活显隐/附件白名单) ### 已知限制(交 TL 裁决) 1. chat/stream 是规划入口(P1 契约):plan_ready 后前端保持心跳;任务事件经 /jobs/{id}/events 订阅(EventSource 首帧快照+回放)。chat/stream 若串流任务事件(后端改契约),sendBioflow 的 applyFrame 已兼容(stage_* 事件双保险处理)。 2. 任务创建前拖入的文件(Composer 附件)只在任务已存在时上传;任务未创建时由 FlowFileCard 阶段引导卡处理——按 FR-BIO-005/006 设计(缺文件时后端发 stage_await_files)。 3. EventSource 断线重连依赖浏览器内建行为 + 首帧快照整体刷新(FR-BIO-014);如需手动退避重连需 TL 指示。 4. 进度卡相位色映射:阶段序号 → 五相位色循环(PipelineCard 同款令牌);阶段与相位的语义映射表由后端 plan 决定,前端只取色。 5. FlowFormCard「改参数重跑」表单值空提交时走 rerun 空参数(后端按默认值);目录 schema 拉取失败降级空表单。 --- ## P3 报告闭环(完成) ### 完成清单 | 模块 | 说明 | |---|---| | 后端增量(草稿,交 TL 审) | sdk/app/services/docgen/templates/bioflow_report.html + bioflow_report.css(Story 安全 CSS 子集,双渲染纪律) | | templating_bioflow.py(新模块,交 TL 审) | fig:// 图引用渲染( → base64 内嵌 + bio-figure 类;未知 id → bio-fig-placeholder 占位降级不报错;TC-BIO-FLOW-005/006);bioflow-fig:data HTML 注释块解析映射;render_bioflow_report 纯同步纯函数绝不抛异常(异常回落 document 兜底,templating.render_html 既有路径零改动) | | docgen_patch(草稿,交 TL 审) | get_artifact_html 仅在 template_name=='bioflow_report' 时增量分支(import 一行 + 分支 7 行);templating.py 既有函数零改动;index.json 不动(docgen 团队 registry 用例断言 keys==7) | | 前端 stores/bioflow.js | registerReport(BFF /api/bioflow/reports/register,template_name='bioflow_report' 与 A2 对齐;localStorage 防重幂等;失败不阻断对话)、reviseReport(FR-BIO-019) | | chat.sendBioflow | job_done → 自动报告登记(fire-and-forget);DocPane 复用零改造(预览走既有 /api/docgen/artifacts/{id}/html 白底 Shadow DOM) | ### 自测结果 - 前端:report.test.js 7 通过(fig:// 渲染兜底替换/未知 id 降级/多图混合;registerReport 字段齐全/防重幂等/失败不抛;reviseReport 分发) - 后端离线验证(服务器 venv 实测,stub pymupdf + markdown-it 直测纯函数——md2pdf import 链与既有 templating.py 相同,生产 BFF venv 有 pymupdf 不受影响):fig:// 替换无残留、base64 内嵌、未知 id 占位、资产加载、异常兜底不抛全过;本地 BANNED_PATTERNS 同款 CSS 自检全过 ### 已知限制(交 TL 裁决) 1. fig 数据块协议为「HTML 注释 」(markdown-it 不渲染注释,PDF 导出亦无残留);报告生成阶段(后端报告链)需按此协议写入——协议写入本报告供 P6/报告链侧对齐。 2. 报告登记防重是前端 localStorage 尽力而为;doc_artifacts 无 job_id 唯一约束,BFF 落库重复登记会产生重复行(需 TL 裁决 BFF 侧幂等或 DB 唯一索引)。 3. revise 端点 P1 为最小接口(无绘图目标 422);绘图阶段重跑后新图回填报告(TC-BIO-API-085)依赖报告链实现,前端侧 revise 成功后建议触发 DocPane 重取 html(renderNonce 机制已存在,若报告已登记为 artifact 可直接 docgen.reload()——接入点待 TL 确认 report_artifact → artifact_id 映射)。 4. 生信报告登记后「文档 TAB 出现报告」依赖 BFF 报告登记落库 + 前端 artifact 列表刷新;当前无「按 session 拉取 artifacts」端点调用点(docgen 既有链路按需拉取),接入点交 TL 裁决。 5. DocPane 白底预览(TC-BIO-FLOW-007)由既有 .doc-host background #ffffff 保证(2026-09-04 修复留存),本小期未改 DocPane(零改造目标达成)。 --- ## P4 存档与复用(完成) ### 完成清单 | 模块 | 说明 | |---|---| | FlowArchiveCard | 存档提示卡全交互(命名/描述/存档/放弃);存档成功块状态 done+result 三要素展示(名称/位置/大小);存档失败可重试;放弃后卡片消失(v-if)同一任务不再提示(store dismissed) | | FlowFormCard 复用模式 | mode='reuse'(bioflow_reuse 块):预填值来自 prefill({value, source:'archive', archiveName})、来源标注「默认值来源:存档 XXX」、标题「复用存档「XXX」发起新任务」、确认按钮创建任务(POST archives/{id}/run,后端合并存档参数);Esc 不改回(存档值即默认) | | stores/bioflow.js | archiveJob(存档+状态机 pending→archiving→done/error)、dismissArchive(无请求无副作用)、loadReusePrefill(存档参数→来源标注=存档名)、runArchive(复用发起返回新任务) | | stores/chat.js | showReuseForm(把 bioflow_reuse 块挂到当前会话助手消息;BioArchivePane 复用发起后消息流出预填表单) | | AssistantMessage | bioflow_reuse 块分支(FlowFormCard 同卡渲染) | ### 自测结果 archive.reuse.test.js:6 通过(预填值=存档值+来源标注=存档名、确认创建发出 archives/{id}/run 且新任务 job-9 入块、store.runArchive 面板路径、存档成功三要素写回、放弃 dismissed 不重复提示、名称空禁用不发空 name 请求)。 另有 cards.test.js 中 FlowArchiveCard 动作矩阵 12 用例(P2 已计入)。 ### 已知限制(交 TL 裁决) 1. 存档状态回复(FR-BIO-021)为任务流内降级形态:存档成功后 FlowArchiveCard 原地展示三要素。若后端 job_archived 事件携带 archive 详情(当前 P1 事件只含 archive_id),消息更新器可再追加独立「存档状态回复」文本块——当前实现已覆盖验收三要素。 2. 复用句式(「用 XXX 存档任务的方法帮我跑 yyy」)的候选装载依赖后端 plan_ready.reuse_archive(P1 已实现);前端路径卡自动选中唯一候选(selected=0)并显示复用徽章。 3. 面板「复用发起」当前打开预填表单到消息流并切生信任务 TAB;按名称模糊匹配复用(archives/run by name)未接 UI 入口(意图路由已支持),待 TL 裁决是否需要面板内名称搜索入口。 --- ## P5 生信任务面板(完成) ### 完成清单 | 模块 | 说明 | |---|---| | BioJobsPane | 任务列表(session-item 形态:标题 13px + 状态徽章 + 进度百分比);阶段 DAG(§8.6 纵向 2px hairline 连接线 + 节点 8px 圆点按阶段状态取色);点击阶段行打开 manifest+日志尾(code-block mono 12px code-bg 滚动);重跑失败阶段(rerunStageForJob 逐个);删除(running 禁用 409 语义 + 二次确认层 + 取消无请求);空态/加载/错误态 | | BioArchivePane | 档案列表(标题+人类可读大小+时间+复用次数);详情回看(阶段链/参数 JSON/产物清单/报告 iframe 预览 src=/api/bioflow/archives/{id}/report);删除(二次确认);复用发起(装载预填 → 消息流表单 → 切生信任务 TAB);空态/加载/错误态 | | BenchPanel.vue | 生信 TAB(生信任务/生信档案)按探活显隐(FR-BIO-025:onMounted probe,online 才渲染);biojobs/bioarchive 面板分支挂载 | | AppShell.vue | 移动端 tab 条 overlayTabs 同源探活显隐(TAB 数断言随改,见下) | | 探活显隐 | 启动探测 GET /api/bioflow/health(timeout 5s);BFF 反代未开 404/不可达 502/503 → availability=offline → 隐藏生信 TAB 与 Composer 生信分流(只部署 rag 的前端自动退化为无生信界面 FR-BIO-027) | ### 自测结果 - panes.test.js:18 通过(TC-BIO-JOB/PANE 全状态:列表/详情/DAG 取色/manifest 浏览/重跑/删除确认与取消/running 禁用/空态/错误态/复用发起块挂载/iframe 报告/大小格式) - benchpanel.bioflow.test.js:5 通过(探活成功 7 TAB 断言(既有 5+生信 2)、探活失败隐藏 2 TAB、强制重探恢复显示、切生信任务 TAB 渲染 BioJobsPane、切生信档案 TAB 渲染 BioArchivePane) - 既有 benchpanel.test.js(5 用例「五 tab 长度 5」断言):探活失败态下仍通过(bioflowHealth mock 未定义时 probe 捕获 offline→不追加 TAB);appshell.test.js 7 用例全过 ### 已知限制(交 TL 裁决) 1. 既有 benchpanel.test.js 的 TAB 断言(5 个)在测试环境探活为 offline 时保持原断言成立(生信 TAB 不出现),生产环境探活成功后为 7 个 TAB——TAB 数断言随探活状态变化是 FR-BIO-025 的预期行为;如需测试侧固定 7 TAB 断言,需在 benchpanel.test.js 补 bioflowHealth mock(红线外文件 tests/,交 TL 裁决是否由 T 轮次统一改)。 2. BioJobsPane 详情来自列表行内 stages(list_jobs 返回 stages_count 但非全量 stages 时,点击加载 getJob 详情补齐);当前实现优先展示列表行内 stages,详情拉取成功后经 selectedJob 计算属性自动更新。 3. 任务列表轮询:当前打开面板时加载一次 + 手动重载;运行中任务实时刷新依赖 /jobs/{id}/events 订阅(消息流进度卡已订阅);面板级轮询(5s)未实现,交 TL 裁决是否需要(TC-BIO-JOB-011 实时更新)。 4. 档案详情 products 字段依赖后端 archive 详情返回文件清单(P1 契约 get_archive 返回 stage_chain/params/report_artifact;products 字段若未返回则空态显示)。若 TL 要求产物清单,需后端 archives 详情补充 products 字段(写入报告交 TL 转 A2)。 --- ## 改动文件总表(服务器仓库 feature/bioflow-conversation-orchestration) 新增: - ui/src/i18n/bioflow.js - ui/src/utils/intent.js - ui/src/api/bioflow.js - ui/src/stores/bioflow.js - ui/src/components/chat/FlowPathCard.vue / FlowFormCard.vue / FlowFileCard.vue / FlowProgressCard.vue / FlowArchiveCard.vue - ui/src/components/bench/BioJobsPane.vue / BioArchivePane.vue - tests/frontend/unit/bioflow/(9 个测试文件) - sdk 草稿(未合入 sdk/ 树,交 TL 审):sdk/app/services/docgen/templates/bioflow_report.{html,css} + templating_bioflow.py + docgen 补丁说明 修改(增量,红线零触碰): - ui/src/stores/chat.js(+681 行:sendBioflow/更新器/上传/路径登记/showReuseForm/retry 分支) - ui/src/components/chat/AssistantMessage.vue(五类块分支) - ui/src/components/chat/Composer.vue(bioflow 分流) - ui/src/components/bench/BenchPanel.vue(生信 TAB 探活显隐) - ui/src/components/layout/AppShell.vue(移动端 tab 条)