Files
happy-life-star/docs/superpowers/plans/2026-07-26-detail-clarification-card-count-fix.md
T

7.3 KiB
Raw Blame History

详情页澄清选项卡显示不全修复 实施计划

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 修复后端 forwardSse 首次 stream 中第一个 clarification_card 因 sessionId 为 null 不累积的 bug,使详情页澄清选项卡数量与生成页完全一致。

Architecture:ShortNovelServiceImpl.forwardSse 的事件循环中,每次解析 SSE 事件后,从事件顶层session_id 同步 currentSessionId[0](与前端 ScriptView.vue:1805 取 sessionId 的方式对齐)。这样无论 status 事件是否在 payload 内携带 session_id,只要事件顶层有 session_id,首次 stream 的 currentSessionId[0] 就能被正确设置,首次 stream 里的 clarification_card 就能被累积。

Tech Stack: Java 17 / Spring Boot 2.7.18 / fastjson2 / OkHttp / MySQL / Maven / Python 部署脚本 / H5 端到端验收

Global Constraints

  • 编译命令:mvn clean install -DskipTests(禁止 mvn clean compile
  • 部署命令:python deploy.py backend(根目录脚本)
  • 部署前必须本地编译通过
  • 部署后必须通过 H5 端到端验收(Console 0 新增错误 + Network 接口正常)
  • 注释必须使用中文
  • 禁止任何形式的 mock、兜底、默认值掩盖错误
  • 只改后端 1 个方法(forwardSse),零前端改动,零数据库变更

Task 1: 后端修复 forwardSse 顶层取 session_id

Files:

  • Modify: server/src/main/java/com/emotion/service/impl/ShortNovelServiceImpl.java:304-308forwardSse 方法的事件循环内,status 处理之前)

Interfaces:

  • Consumes: 上游 SSE 事件 JSON 结构(事件顶层 session_id 字段与 type 同级)
  • Produces: currentSessionId[0] 在首次 stream 里也能被正确设置(不再是 null)

背景

  • 根因:上游 SSE 事件的 session_id 在事件顶层(与 type 同级),但后端 forwardSse 行 312-314 从 payload.getString("session_id") 取,取不到。导致首次 stream 的 currentSessionId[0] 保持 nullknownSessionId=null)。
  • 数据证据DB 中 3 个有 clarification 的 conversation 全部是 clarification_question=2 + clarification_answer=3。第一个 clarification_questioncurrentSessionId[0]==null 不累积。
  • 修复思路:在 status 处理之前,从事件顶层取 session_id 同步 currentSessionId[0](与前端 ScriptView.vue:1805-1806 逻辑对齐)。

步骤

  • Step 1: 在 forwardSse 事件循环中插入从顶层取 session_id 的代码

打开 server/src/main/java/com/emotion/service/impl/ShortNovelServiceImpl.java,定位到 forwardSse 方法内的事件循环。当前代码(行 304-311):

try {
    JSONObject event = JSON.parseObject(dataStr);
    String type = event.getString("type");
    long eventTimestamp = System.currentTimeMillis();
    log.info("[ShortNovel SSE] 处理事件: type={}, timestamp={}", type, eventTimestamp);

    // 拦截 status 事件,缓存 sessionId → originalQuery 映射(供 followup 兜底)
    if ("status".equals(type)) {

log.info(...) 之后、// 拦截 status 事件 注释之前,插入以下 5 行代码

                                // 从事件顶层取 session_id 同步 sessionId
                                // 上游事件结构与前端对齐:session_id 与 type 同级,不在 payload 内
                                // 修复:首次 stream 里 status 处理从 payload 取不到 session_id,导致 currentSessionId 保持 null
                                // 第一个 clarification_card 因 sessionId 为 null 不累积,详情页少显示第一个选项卡
                                String topSessionId = event.getString("session_id");
                                if (topSessionId != null && !topSessionId.isEmpty()) {
                                    currentSessionId[0] = topSessionId;
                                }

插入后整体结构(行 304-320):

try {
    JSONObject event = JSON.parseObject(dataStr);
    String type = event.getString("type");
    long eventTimestamp = System.currentTimeMillis();
    log.info("[ShortNovel SSE] 处理事件: type={}, timestamp={}", type, eventTimestamp);

    // 从事件顶层取 session_id 同步 sessionId
    // 上游事件结构与前端对齐:session_id 与 type 同级,不在 payload 内
    // 修复:首次 stream 里 status 处理从 payload 取不到 session_id,导致 currentSessionId 保持 null
    // 第一个 clarification_card 因 sessionId 为 null 不累积,详情页少显示第一个选项卡
    String topSessionId = event.getString("session_id");
    if (topSessionId != null && !topSessionId.isEmpty()) {
        currentSessionId[0] = topSessionId;
    }

    // 拦截 status 事件,缓存 sessionId → originalQuery 映射(供 followup 兜底)
    if ("status".equals(type)) {
  • Step 2: 本地编译验证

Run: cd server && mvn clean install -DskipTests Expected: BUILD SUCCESS,零错误。

  • Step 3: 部署到远程服务器

Run: python deploy.py backend Expected: 部署脚本输出"部署成功",服务重启完成。 如果部署脚本在 Windows 报 PATH 问题,手动执行:

scp server/target/emotion-single-1.0.0.jar root@101.200.208.45:/data/programs/emotion-museum/
ssh root@101.200.208.45 "cd /data/programs/emotion-museum && ./restart.sh emotion-museum-single"
  • Step 4: H5 端到端验收
  1. 启动 mini-program H5python dev-services.py start mini-program(端口 5180
  2. 浏览器访问 http://localhost:5180/#/pages/main/index?tab=script
  3. 手动完成一次新的小说生成(包含至少 2 轮澄清)
  4. 生成过程中记录生成页显示的选项卡数量 N
  5. 生成完成后,进入该剧本的详情页(通过列表页点"历史"进入 ScriptLibraryView,再点击对应剧本)
  6. 验证详情页显示 N 个澄清选项卡(与生成页完全一致)
  7. 浏览器 Console 检查:0 新增错误(既有的 uni.getRecorderManager 错误除外)
  8. Network 面板:listByConversation 接口响应中 clarification_question 类型消息数量 = 生成页澄清轮数
  • Step 5: 提交代码
cd G:\IdeaProjects\emotion-museun
git add server/src/main/java/com/emotion/service/impl/ShortNovelServiceImpl.java
git commit -m "fix(server): 修复 forwardSse 首次 stream 第一个 clarification_card 不累积的 bug

上游 SSE 事件的 session_id 在事件顶层(与 type 同级),后端原从 payload.session_id 取导致首次 stream 取不到,
currentSessionId 保持 null,第一个 clarification_card 不累积。
改为从事件顶层取 session_id 同步 currentSessionId(与前端 ScriptView.vue:1805 逻辑对齐)。
修复后新剧本详情页澄清选项卡数量与生成页完全一致。"

验收标准

  • 本地 mvn clean install 编译通过
  • 部署到远程服务器成功
  • 新剧本详情页澄清选项卡数量 = 生成页澄清选项卡数量
  • Console 0 新增错误
  • 老剧本(3 个已有 conversation)保持现状,仍显示 2 个 card(数据已永久丢失,符合预期)