跳转至

P1.UA21R1.F4-phase-popup-frontend · PhaseModulePopup 双击悬浮窗(对标 FftModulePopup)

Worker:ClaudeA · 前端 (frontend_vue3) / 预计:0.5d / 优先级:P1 / 状态:ready(建议 blocked-by F1-R1 但文件正交) 隔离:🧵 文件隔离(同 worktree 同 branch · ADR-21-R1 fork 3 · 与 F2-R1 / F6-R1 文件正交可并行)


🔍 触发与解锁链

触发 状态 影响
用户 10:24 反馈点 1 "phase 和 transfer 功能要和当前已经是先的 fft module 对标;当前是双击直接悬浮弹窗 fft 窗体"
ADR-21-R1 §3.3-R1 Phase 双路径 路径 A(主):双击 mini-node → PhaseModulePopup;路径 B(辅助):右 dock(由 F2-R1 cleanup 后保留)
FFT popup 范式标杆已就位 components/popups/FftModulePopup.vue 374 行 + props {config, x, y, zIndex} + emits {close, bringToFront, move} + usePopupModuleManager
LinkEditor 双击协议骨架已存在 LinkEditor.vue 行 129 onModuleDoubleClick + 行 353 onSubgraphNodeDblClick + 行 1610 实现 · phase mini-node 双击仅需补路由
F3 phase 算法层 zombie 8eaaf40 typeId 0x100E0004 + frame schema MeterFrame_Phase 已锁(ADR-12 §3.4)· popup 直接消费

→ 本 R1 hotfix 是 popup 新建型 · 工时短(0.5d)· 改动小 · 与 F2-R1 / F6-R1 可并行 · 用户实测核心:phase mini-node 双击 → 浮动 PhaseModulePopup ≤ 200ms · 三段图渲染(wrapped/unwrapped/groupDelay)


任务定义(基于 ADR-AIOS-21-R1 §3.3-R1)

实施 ADR-21-R1 §3.3-R1 Phase Module 路径 A(双击悬浮窗主入口):

  • 新建 PhaseModulePopup.vue:对标 FftModulePopup.vue(374 行)· props {config: PhaseModuleConfig, x, y, zIndex} + emits {close, bringToFront, move} · template macOS 风格 header(交通灯 + 拖拽)+ 三段图区(wrapped/unwrapped/groupDelay 切换)+ chart 渲染(echarts 或 canvas · 与现有 PhaseChart 子组件复用 · F4 2d5de9c 落地版 PhaseChart 保留)
  • LinkEditor onModuleDoubleClick 加 phase 路由:行 129 @dblclick.stop="onModuleDoubleClick($event, module)" 已有骨架 · 函数体内补:若 module.moduleId === 'phase-module' 或 typeId 0x100E0004 → 调 usePopupModuleManager.openModulePopup('phase-module', module.instanceId, x, y)
  • usePopupModuleManager 注册 phase-module:若管理器需扩 module 类型映射(eg. moduleId → popup component)· 加 phase-module: PhaseModulePopup(VueUse defineAsyncComponent 加载)
  • frame 消费:popup 内调 useDockMeterFrame(F2-R1 抽离后)或临时调 useChainNodeMetadata + WebSocket 直接消费 phase frame · 与 dock 路径独立 store(ADR-21-R1 §3.3-R1 ② "popup ↔ dock 状态独立")
  • 不动:F3 8eaaf40 算法层(typeId / frame schema)· F2-R1 dock 路径(DrawerDockPhase 由 F2-R1 cleanup)· LinkEditor 行 353/1610 onSubgraphNodeDblClick(子图协议无关)

严守保留(零回归):F3 phase 算法层 + frame schema(ADR-12 §3.4 MeterFrame_Phase)+ LinkEditor 现有双击协议骨架 + usePopupModuleManager 现有 API · 不破坏 FFT/RMS/Scope popup 现有行为(对标参照 · 不冲突)。


完整 prompt(直接复制粘贴 worker 终端)

[U-thread]   P1.UA21R1.F4-phase-popup-frontend
[部门]       前端 (frontend_vue3) · 推荐 skill: vuejs-typescript-best-practices
[Worker CWD] d:/work/25_claude/workspace/AlgoDepartment/04_development/
[Occupies]   P1.K-xilink-popup(写 · phase popup 新建)+ P1.K-xilink-canvas(读 · LinkEditor 双击协议)
[隔离]       🧵 文件隔离 · 与 F2-R1(dock 5 meter cleanup)/ F6-R1(transfer popup)文件正交可并行 · 不动 stages/xitest/* / xitune/* / xiforge/* · 不动 dsp_algo/* · 不动 backend_csharp/*
[优先级]     P1 · 0.5d · ADR-21-R1 fork 3 · popup 新建型 hotfix
[ADR]        d:/work/25_claude/workspace/AlgoDepartment/06_docs/site-build/docs/08-implementation/40-aios/ADR/ADR-AIOS-21-R1-dock-three-selectors-and-popup-entries.md(必读 §3.3-R1 Phase 双路径 + §4.2 F4-R1 行)
[业务行为契约引用] ADR-21-R1 §3.3-R1 ① 双路径契约(props/emits 对标 FftModulePopup) + ② 收敛判据(双击 ≤ 200ms · 三段图 popup vs dock 一致 · popup ↔ dock 独立) + 用户原话 6/15 10:24 verbatim

[参考文档](绝对路径)
  - ADR 主文档:d:/.../docs/08-implementation/40-aios/ADR/ADR-AIOS-21-R1-dock-three-selectors-and-popup-entries.md
  - 父 ADR:d:/.../docs/08-implementation/40-aios/ADR/ADR-AIOS-21-xilink-dock-and-analysis-modules.md(已 partially-superseded · §3.3 算法部分保留)
  - F4 supersede 标本:d:/.../docs/08-implementation/40-aios/prompts/done/ADR-AIOS-21/P1.A21.F4-phase-module-frontend--2d5de9c.md(看 DrawerDockPhase 实装 · 本 fork 不删 · 但加 popup)
  - F3 zombie 标本(算法层保留):d:/.../docs/08-implementation/40-aios/prompts/done/ADR-AIOS-21/P_dsp.A21.F3-phase-module-algorithm--8eaaf40.md(看 typeId + frame schema)
  - **FFT popup 范式标杆**(对标必读):d:/.../04_development/frontend_vue3/src/components/popups/FftModulePopup.vue(374 行 · 完整对标)
  - 全局管理器:d:/.../04_development/frontend_vue3/src/composables/usePopupModuleManager.ts(看 openModulePopup API)
  - 现状必读:
    · frontend_vue3/src/components/popups/FftModulePopup.vue(全文 · template + script + style 完整对标)
    · frontend_vue3/src/components/popups/RMSMeterModulePopup.vue(辅助参考 · ADR-17 F6 范式)
    · frontend_vue3/src/components/popups/ScopeModulePopup.vue(辅助参考)
    · frontend_vue3/src/composables/usePopupModuleManager.ts(全文 · 看 openModulePopup / closeModulePopup / 浮窗 store)
    · frontend_vue3/src/stages/xilink/LinkEditor.vue(行 120-160 + 行 1600-1640 · 看 onModuleDoubleClick 现有实现 · 补 phase 路由)
    · frontend_vue3/src/stages/xilink/drawers/DrawerDockPhase.vue(F4 2d5de9c · 看 PhaseChart 子组件 · popup 复用)
    · frontend_vue3/src/stores/moduleLibrary.ts(若需扩 phase-module 元数据)

【背景】
用户 10:24 原话第 1 点:"phase 和 transfer 功能要和当前已经是先的 fft module 对标;当前是双击直接悬浮弹窗 fft 窗体"
- 现状(F4 2d5de9c 落地后):xilink 链路 phase mini-node 仅有 dock 入口(DrawerDockPhase)· 没有双击 popup 路径
- ADR-21 起草时漏写了"对标 FFT popup 双击"协议 · ADR-21-R1 §3.3-R1 修订加双路径
- FFT popup 范式标杆已就位:components/popups/FftModulePopup.vue(374 行) + usePopupModuleManager + LinkEditor 行 129 onModuleDoubleClick 骨架
- 本 fork 仅新建 PhaseModulePopup.vue + 加 phase 路由 + popup 注册 · 0.5d 工时

【执行步骤】

Step 0 · 真值核查(必跑 · 0.1d)
- git status / git pull origin xistudio --no-rebase
- read frontend_vue3/src/components/popups/FftModulePopup.vue 全文(374 行 · 对标范式 · template + script + style)
- read frontend_vue3/src/composables/usePopupModuleManager.ts 全文(API 签名 + 浮窗 store)
- read frontend_vue3/src/stages/xilink/LinkEditor.vue 行 120-160 + 行 1600-1640(onModuleDoubleClick 现有实现 · 找补 phase 路由位置)
- read frontend_vue3/src/stages/xilink/drawers/DrawerDockPhase.vue(F4 2d5de9c · 看 PhaseChart 子组件 props/emits · popup 复用 chart 渲染)
- grep -r "phase_v1\|phaseModule\|phase-module" frontend_vue3/src(看 phase-module 在 moduleLibrary / typeId 注册位置)
- 输出真值核查到 commit body:
  · FftModulePopup props/emits 完整签名(给 PhaseModulePopup 对齐)
  · usePopupModuleManager.openModulePopup API 签名(给 LinkEditor 双击补路由用)
  · PhaseChart 子组件接口(popup 复用 chart 渲染)
  · phase-module typeId 0x100E0004 + moduleId 字符串(LinkEditor 双击判定用)

Step 1 · 新建 PhaseModulePopup.vue(0.2d · 对标 FftModulePopup)
- 新建 frontend_vue3/src/components/popups/PhaseModulePopup.vue
- 严格对标 FftModulePopup.vue 骨架:
  · props: `{ config: PhaseModuleConfig, x: number, y: number, zIndex: number }`
  · emits: `{ close: [], bringToFront: [], move: [x: number, y: number] }`
  · template:macOS 风格 header(交通灯 ⊗ + 拖拽 + 标题 "Phase Module")+ 主区(三段图切换 tab + chart 区)
  · 三段图切换:wrapped(相位 [-180,180]°) / unwrapped(解卷绕单调) / groupDelay(ms)· 按钮 tab 或 select 下拉
  · chart 区:复用 DrawerDockPhase 内 PhaseChart 子组件(F4 2d5de9c 落地)· 传 displayMode prop 切换三段图
  · 拖拽:沿用 FftModulePopup 拖拽实现(mousedown.stop on header · pointermove 计算 x/y emit 'move')
  · 默认尺寸:600×380(与 FftModulePopup 一致)· 可 resizable
  · macOS 风格 + theme-aware(对齐 ADR-12 §2.11 第 9 项 design-token · 不硬编码 hex)
- script:
  · 调 useDockMeterFrame(F2-R1 抽离后)或 useChainNodeMetadata + WS 直接消费 phase frame
  · displayMode ref 默认 'wrapped'
  · onMounted 拉 frame 数据 · onUnmounted 反订阅
  · 5s timeout fallback(沿用 ADR-21-R1 §3.3-R1 ③ 失败回退)

Step 2 · usePopupModuleManager 注册 phase-module(0.05d)
- 编辑 frontend_vue3/src/composables/usePopupModuleManager.ts(若需扩)
- moduleId → popup component 映射加:`phase-module: defineAsyncComponent(() => import('@/components/popups/PhaseModulePopup.vue'))`
- 若管理器已支持泛型 module 类型 · 仅需在 openModulePopup 调用方传 moduleId='phase-module' · 不改管理器本身

Step 3 · LinkEditor 补 phase 双击路由(0.1d)
- 编辑 frontend_vue3/src/stages/xilink/LinkEditor.vue
- 找行 129 `@dblclick.stop="onModuleDoubleClick($event, module)"` 上下文
- 找 onModuleDoubleClick 函数实现(grep 后 read 上下文 · 应在行 1500+ 区)
- 函数体内加:若 `module.moduleId === 'phase-module'` 或 `module.typeId === 0x100E0004` → 调 `usePopupModuleManager.openModulePopup('phase-module', module.instanceId, $event.clientX, $event.clientY)`
- 不动行 353 onSubgraphNodeDblClick(子图协议无关)
- 不动行 1610 onSubgraphNodeDblClick 实现

Step 4 · vitest 单测(0.1d)
- 新增 frontend_vue3/tests/components/PhaseModulePopup.test.ts(≥ 5 case):
  · case 1:渲染 props {config, x:100, y:100, zIndex:10} · template 顶级 div 含正确 style
  · case 2:close 按钮 click · emit 'close' 事件
  · case 3:header mousedown.capture · emit 'bringToFront'
  · case 4:displayMode 切换(wrapped → unwrapped → groupDelay)· chart 区 PhaseChart 子组件 props 同步更新
  · case 5:onUnmounted 反订阅 useDockMeterFrame(mock)

Step 5 · build + test + 手动 e2e(0.05d)
- cd frontend_vue3
- npm run typecheck(零错误)
- npm run test:unit(基线 +5 case 全绿 · 已知 3 fail 不增)
- 手动 e2e(浏览器):
  · npm run dev
  · 进 P1-xilink stage · 加载链路含 phase-module 节点(typeId 0x100E0004)
  · 双击 phase mini-node → PhaseModulePopup 浮现 ≤ 200ms · 默认位置不超 viewport
  · 切 displayMode wrapped/unwrapped/groupDelay · chart 区切换渲染(三段图)
  · 拖拽 popup header · 验位置变更 + emit 'move'
  · 关 popup(× 按钮)· 验消失 · phase mini-node 在链路中状态保持
  · popup ↔ dock 独立性测试:同时打开 popup + dock(由 F2-R1 cleanup 后)· 切 dock 节点 · popup 不受影响

Step 6 · commit + push(0.05d)
- git add frontend_vue3/src/components/popups/PhaseModulePopup.vue(新建) \
          frontend_vue3/src/composables/usePopupModuleManager.ts(若改) \
          frontend_vue3/src/stages/xilink/LinkEditor.vue \
          frontend_vue3/src/stores/moduleLibrary.ts(若改) \
          frontend_vue3/tests/components/PhaseModulePopup.test.ts
- git commit subject + trailer 见下
- git push origin xistudio
- 反馈 Cline-AIOS:zombie hash + 浏览器实测截图(双击 mini-node → popup 浮现)+ 三段图切换截图

【验收】

形式合规:
- [ ] npm run typecheck 零错误
- [ ] npm run test:unit 全绿(基线 +5 case · 已知 3 fail 不增)
- [ ] 仅修动 4-5 文件(1 新建 popup + 1-2 改 LinkEditor/manager + 1 tests)
- [ ] 不破坏 FftModulePopup / RMSMeterModulePopup / ScopeModulePopup 现有行为
- [ ] 不破坏 LinkEditor 行 353/1610 子图双击协议
- [ ] 不动 dock 路径(F2-R1 范畴)· 不动 dsp_algo F3 算法层

业务行为契约(端到端真值 · 必跑):
- [ ] **双击 phase mini-node → PhaseModulePopup 浮现 ≤ 200ms**(ADR-21-R1 §3.3-R1 ② 关键判据)
- [ ] popup props/emits 严格对标 FftModulePopup({config, x, y, zIndex} + close/bringToFront/move)
- [ ] 三段图切换(wrapped/unwrapped/groupDelay)chart 区渲染正确
- [ ] popup 拖拽 + 关闭 + bringToFront 行为与 FftModulePopup 一致
- [ ] popup ↔ dock 状态独立(同时打开互不影响)
- [ ] 5s timeout fallback 在 mock WS 永不响应时触发

【commit】
subject:`feat(P1.UA21R1.F4-phase-popup-frontend): 新建 PhaseModulePopup 双击悬浮窗对标 FftModulePopup · ADR-21-R1 §3.3-R1`

trailer(必须精确):
[step=6/6] [pid=P1] [uid=UA21R1.F4-phase-popup-frontend] [occupies=P1.K-xilink-popup+P1.K-xilink-canvas]
[files=frontend_vue3/src/components/popups/PhaseModulePopup.vue, src/composables/usePopupModuleManager.ts, src/stages/xilink/LinkEditor.vue, src/stores/moduleLibrary.ts, tests/components/PhaseModulePopup.test.ts]
[isolation] file(同 worktree 同 branch · 与 F2-R1/F6-R1 文件正交)
[adr] ADR-AIOS-21-R1 §3.3-R1 + §4.2 F4-R1
[derived_from] supersede F4 2d5de9c 部分(加 popup · DrawerDockPhase 由 F2-R1 cleanup · 不删)
[parent_zombie] 8eaaf40(F3 算法层 · 复用)+ 2d5de9c(F4 frontend · 部分保留 PhaseChart)
[truth-check] FftModulePopup 范式对标点=<行号> · LinkEditor 双击路由补点=<行号> · phase typeId=0x100E0004
[acceptance] 双击 mini-node → popup ≤ 200ms + 三段图 + popup/dock 独立

【禁止】
1. ❌ 不动 backend_csharp/ / dsp_algo/ / contracts/
2. ❌ 不动 F3 8eaaf40 算法层(typeId / frame schema)
3. ❌ 不动 dock 路径(DrawerDockPhase 由 F2-R1 cleanup · 本 fork 仅 popup)
4. ❌ 不动 LinkEditor 行 353/1610 子图双击协议
5. ❌ 不破坏 FftModulePopup / RMSMeterModulePopup / ScopeModulePopup 现有行为(grep 三个文件 · 仅参照不改)
6. ❌ 不引入新 chart 库(PhaseChart 沿用 F4 2d5de9c · echarts/canvas 依赖不动)
7. ❌ 不在 popup 内做数学计算(L3 前端零数学 · 沿用 ADR-07 三层分工铁律)
8. ❌ 硬编码 hex 颜色(对齐 ADR-12 §2.11 第 9 项 · design-token)
9. ❌ commit message 缺三元组 trailer 任一字段

解锁链(本任务 zombie 后)

  • ✅ phase 双路径全打通(popup 主入口 + F2-R1 cleanup 后 dock 辅助入口)
  • ✅ 配合 F1-R1 + F2-R1 + F6-R1 全 zombie → P_e2e.A21R1.F7 e2e ready
  • 🏆 用户实测"phase 双击 → 浮动窗"对标 FFT 范式达成

风险评估

风险 缓解
⚠️ FftModulePopup 374 行对标范式细节多(macOS 交通灯 / 拖拽 / theme-aware) Step 0 必读 FftModulePopup 全文 · Step 1 严格 1:1 对标 · 不自创风格
⚠️ LinkEditor onModuleDoubleClick 现有实现可能已对其他 module(fft/rms/scope)有路由 Step 0 read 函数体 · 加 phase 路由不破坏现有 fft/rms/scope 路由 · switch case 或 if-else 串接
⚠️ usePopupModuleManager 可能不支持泛型 module 类型扩展 Step 0 看 manager API · 若不支持需 Step 2 扩 module 类型映射(defineAsyncComponent + Map)· 控制改动 ≤ 20 行
⚠️ PhaseChart 子组件 props/emits 与 popup 内调用方式可能不匹配 Step 0 read DrawerDockPhase 看 PhaseChart 接口 · popup 内严格对齐 props · 若需调整 PhaseChart 接口 · 标 [need: PhaseChart-props-extension]
⚠️ frame 数据通路(useDockMeterFrame 由 F2-R1 抽离)若 F2-R1 未 zombie · 本 fork 暂用 useChainNodeMetadata + WS 直调 Step 1 决策:① 若 F2-R1 已 zombie → 调 useDockMeterFrame ② 否则临时直调 WS · F2-R1 zombie 后小重构
⚠️ popup 默认位置策略(避免溢出 viewport / 多 popup 错开) 沿用 usePopupModuleManager 现有位置分配策略 · 不自创
⚠️ 与 F2-R1 / F6-R1 同 ClaudeA worker 并行 git pull 时序 串行 commit · 文件正交时 git pull --no-rebase 自动合并

历史

时间 事件 hash
2026-06-15 11:30 ADR-21-R1 v0.1 proposed · 起本 R1 hotfix(F4-R1 · ready 状态等用户 accept ADR-21-R1 + start)
(待) dispatched
(待) zombie