Files
happy-life-star/docs/superpowers/specs/2026-06-27-ai-message-card-buttons-design.md
T
peanut e014450aa3 docs:新增 AI 消息卡片功能按钮统一设计文档
- 修复 story-card 展开失效 bug
- 为每条 AI 消息添加完整功能按钮组
- 采用方案 A:在现有单文件组件内修复 + 扩展
2026-06-27 20:40:37 +08:00

5.1 KiB
Raw Blame History

author, created_at, purpose
author created_at purpose
claude 2026-06-27 统一小程序实现心愿页面中所有 AI 消息卡片的功能按钮,并修复 story-card 展开失效 bug

AI 消息卡片功能按钮统一设计

背景

在小程序「实现心愿」页面(mini-program/src/pages/main/ScriptView.vue)中:

  1. 第一个 AI 回复卡片story-card)拥有完整的功能按钮:展开/收起、复制、换个方向、不像我、继续生成、播放。
  2. 后续 AI 消息result-chat-list)只有基础的展开/收起,缺少复制、换个方向、不像我、继续生成、播放。
  3. story-card 展开失效:当用户触发过重新生成(resultHasScriptRepliestrue)后,<template v-if="!resultHasScriptReplies"> 会隐藏整个故事正文和底部展开按钮,导致点击展开无效果。

目标

  • 每条 AI 回复消息卡片都拥有完整的功能按钮(展开/收起、复制、换个方向、不像我、继续生成、播放)
  • 修复 story-card 展开失效的 bug
  • 所有按钮功能正常可用

方案选择

采用 方案 A:在现有单文件组件内修复 + 扩展

  • 不提取独立组件,保持现有文件结构
  • 改动最小、风险低、不引入新文件
  • 后续如有更复杂的差异化需求再升级

详细设计

1. 修复 story-card 展开失效

根因ScriptView.vue 第 192 行的条件包裹

<template v-if="!resultHasScriptReplies">
  <scroll-view v-if="storyCollapsed" ...>
    <text class="story-body">{{ displayedResultContent }}</text>
  </scroll-view>
  <text v-else class="story-body">{{ displayedResultContent }}</text>
  <view class="collapse-row" @click="toggleStoryCollapse">...</view>
</template>

resultHasScriptRepliestrue(有 kind: 'script' 的消息)时,整个故事正文和底部展开按钮被隐藏。

修复:去掉 <template v-if="!resultHasScriptReplies"> 条件包裹,让故事正文始终由 storyCollapsed 控制展开/收起。

副作用story-card 始终显示完整故事正文,与 result-chat-list 中的 script 消息内容重复。这是预期行为——两个卡片独立操作各自内容。

2. 给每条 assistant 消息加功能按钮组

布局:在每条 assistant 消息的内容 + 展开/收起按钮之后,追加一行网格按钮组,2 列布局(与 story-card 的 .result-actions 一致)。

按钮清单(按顺序):

按钮 作用 实现方式
复制 复制该消息正文到剪贴板 uni.setClipboardData
换个方向 进入「换方向」修订确认 复用现有 changeDirection()
不像我 进入「不像我」修订确认 复用现有 notLikeMe()
继续生成 收起故事 + 聚焦输入框 复用现有 continueInChat()
播放 播放 TTS 音频 复用 ttsPlayer.playSource,传 currentResult.id

按钮条件

  • 展开/收起、复制:所有 assistant 消息都有
  • 换个方向、不像我、继续生成、播放:所有 assistant 消息都有(本质上是全局操作,作用在 currentResult 上)
  • 正在 pending 的 assistant 消息不显示按钮组(保持现有逻辑,isAssistantMessage 已排除 pending

3. 新增/修改的事件处理器

  1. copyMessageContent(message)(新增):

    • 复制 message.content 到剪贴板
    • 空内容时 showToast 提示「暂无可复制内容」
    • 埋点 script_message_copy_click
  2. playMessageTts(message)(新增):

    • 调用 ttsPlayer.playSource(currentResult.value?.id || '')
    • 所有消息都播放同一个故事的 TTS(TTS 基于 currentResult 生成)
    • 埋点 script_message_tts_click
  3. toggleMessageCollapse(message)(修改):

    • 补充埋点 script_message_collapse_toggle(与 toggleStoryCollapse 对齐)

4. 样式

为消息卡片内的按钮组新建 .message-actions 样式,复用 .result-actions.action-btn 的视觉风格:

.message-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14rpx;
  margin-top: 16rpx;
}

按钮直接复用 .action-btn 类名,确保视觉与主卡片一致。展开/收起按钮(.message-toggle)保留现有金色调样式,与功能按钮组做视觉区分。

5. 边界情况

场景 行为
空内容的 assistant 消息 复制按钮 showToast 提示「暂无可复制内容」;其他按钮正常可用
pending 中的消息 不显示按钮组(现有逻辑)
user 消息 不显示按钮组
currentResult 时的播放 按钮仍可点击,playSource 会走内部兜底(传空 id

修改范围

仅修改一个文件:mini-program/src/pages/main/ScriptView.vue

模板修改

  1. 去掉第 192 行 <template v-if="!resultHasScriptReplies"> 条件包裹
  2. result-chat-list 的 assistant 消息中添加功能按钮组

脚本修改

  1. 新增 copyMessageContent(message) 方法
  2. 新增 playMessageTts(message) 方法
  3. 修改 toggleMessageCollapse(message) 补充埋点

样式修改

  1. 新增 .message-actions 样式