Files
beige/plans/Clover前端逻辑诊断-数据流与交互.md
yangqianqian 6a2632da70 baseline: Clover 独立仓库首次基线提交
将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。
当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包),
M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:30:22 +08:00

6.7 KiB
Raw Permalink Blame History

Clover 前端逻辑诊断 · 数据流与交互(第一次扒·另一窗口改完需重扒)

你的直觉对了:"功能呈现和数据流转交互太弱"——但弱在数据流架构,不只在界面长相。 扒的是3个zustand store(generation/task/preference) + api.ts + useSse + sse.ts。 ⚠️ 另一窗口正在改前端,本次结论是当前快照,改完重扒对比。


一、先画出前端真实的数据流

┌─ 进任务页 ─────────────────────────────────────────────┐
│ useSse(taskId) 启动                                      │
│   ① 立即 GET /tasks/{id} → hydrateFromTask (回填历史候选) │
│   ② 建 SSE: 先POST换ticket → EventSource连stream         │
│   ③ SSE事件 → handleEvent → 写 generationStore           │
└──────────────────────────────────────────────────────┘
        ↓ 组件从 store 订阅渲染
   text/images页 读 generationStore.textCandidates 等
        ↓ 用户选择
   taskStore.selectedTextIds (纯本地数组)
        ↓ 点"下一步"
   for循环逐个 POST select → router.push 下一页

三个store各管一摊

  • generationStoreSSE进度+候选+飞轮注入(生成态)
  • taskStore当前任务id+已选id数组选择态
  • preferenceStore:飞轮偏好摘要(注入态)

二、数据流的7个弱点每条带代码证据

弱点1策略维度A/B/C在前端被彻底抹平 🔴最关键

  • 后端生图按3套策略各N张pipeline_io.py:201SSE的image_candidate事件带了strategy字段(useSse.ts:104接收了)。
  • generationStore.imageCandidates一维平铺数组(store注释明写"image_candidate无batch字段所以平铺")images页直接grid铺开。
  • 后果:后端辛苦做的"3个叙事方向×N张给你对比挑选"前端变成一堆看不出分组的散图。用户不知道哪些是同一策略、为什么有18张。这是"交互弱"最硬的证据——信息结构在展示层塌掉了

弱点2文案五维分要二次请求补全且每条都重拉整个task 🔴

  • useSse.ts:75-94SSE的text_candidate只推total分五维明细靠再次 GET /tasks/{id} 补全
  • 致命:每来一条文案候选就GET一次整个task(line88)8条文案=8次全量请求每次返回所有候选。N条候选→N次重复拉全量越往后越浪费。
  • 后果五维分有延迟跳变先0后补且网络浪费。交互上是"分数闪一下才出来"。

弱点3选择态是纯本地数组不落后端、刷新即丢 🟡

  • taskStore.selectedTextIds/selectedImageIds 只在内存(line13)。
  • 选文案时toggleTextSelection只改本地数组,点"下一步"才 for循环逐个POST select(text/page.tsx:29-32)。
  • 后果:①选到一半刷新页面,选择全没了 ②多选N条就发N个请求(不是批量) ③选中状态和后端is_selected字段不实时同步。

弱点4跳转用 router.push候选数据靠"重新拉" 🟡

  • 每个环节(text→images→confirm)是独立页面,靠router.push跳转。
  • 进每页 useSsestore.reset()hydrateFromTask重新GET(useSse.ts:21,30)。
  • 后果:环节间无"连续流"感,每跳一页是一次重新加载+重连SSE。confirm页要的已选数据generationStore里还留着的候选filter出来(confirm/page.tsx:22-23)——万一store被reset就空了

弱点5confirm页数据来源脆弱 🟡

  • confirm/page.tsx:22textCandidates.filter(selectedTextIds.includes)拿已选内容。
  • selectedTextIds在taskStore、textCandidates在generationStore两个store没绑定。SSE的reset只清generationStoreselectedTextIds还在taskStore——两者生命周期不一致容易错位。

弱点6错误处理静默吞掉 🟡

  • useSse.ts:37,93 多处.catch(() => {})空吞错误;preferenceStore:31无偏好"不阻塞流程"也静默。
  • 后果:数据没拉到时用户无感知,界面就是"空着",不知道是没数据还是出错了。这放大了"空"的感受。

弱点7SSE的task_done/error事件没驱动UI 🟡

  • useSse.ts:123-127error/task_done/analyze_done/heartbeat全部break空处理。
  • 后果:生成完成了(task_done)前端不弹提示、不自动跳转;出错了(error)也不显式告诉用户。状态机的关键节点在前端是哑的。

三、为什么"交互弱"——根因归纳

表象 数据流根因
图一堆看不出门道 策略维度被平铺抹平(弱点1)
分数闪一下才出 五维分二次请求补全(弱点2)
选着选着没了 选择态纯本地不持久(弱点3)
翻页像重新加载 页面级跳转+每页重连重拉(弱点4)
完成/出错没反馈 关键SSE事件空处理(弱点7)+错误静默(弱点6)

本质:前端是"被动渲染后端推什么显示什么"的薄层,没有自己的"数据组织能力"。后端给的多维数据(策略/评分/角色/理由),前端要么拍平、要么二次拉、要么不展示。不是界面不好看,是数据进了前端没被'组织'成有结构的交互。


四、对照俊达:他的前端为什么"饱满流畅"

俊达界面给人"饱满"感,本质是数据被组织出了层次

  • 同一组图按策略/角色分组对比 → Clover平铺(弱点1)
  • 每个产出带可见的评分/理由/标签 → Clover评分要补拉、理由没全显(弱点2)
  • 操作即时反馈、状态流转有动效 → Clover关键事件空处理(弱点7)
  • 进化页/复盘页是"数据看板" → Clover dashboard是3个按钮

借鉴点(不抄原文)把"后端已有的多维数据"在前端组织成有结构的呈现——分组、即时反馈、状态可见。这是纯前端重构不依赖后端加功能也不碰俊达的knowhow。


五、待重扒清单(另一窗口改完后)

本次基于当前快照。另一窗口改完前端后,重点复查这几项有没有变:

  1. generationStore 的 imageCandidates 有没有改成按strategy分组
  2. useSse 的五维分补全有没有改掉"每条拉全量task"
  3. taskStore 选择态有没有改成持久化/批量提交
  4. 关键SSE事件(task_done/error)有没有接UI反馈
  5. dashboard 有没有加数据看板
  6. images页有没有按A/B/C分组展示

重扒方法对这6个文件做 diff对照本文档逐条核实改了没。本文档是"改之前"的基线。