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

126 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
author: claude
created_at: 2026-06-27
purpose: 统一小程序实现心愿页面中所有 AI 消息卡片的功能按钮,并修复 story-card 展开失效 bug
---
# AI 消息卡片功能按钮统一设计
## 背景
在小程序「实现心愿」页面(`mini-program/src/pages/main/ScriptView.vue`)中:
1. **第一个 AI 回复卡片**`story-card`)拥有完整的功能按钮:展开/收起、复制、换个方向、不像我、继续生成、播放。
2. **后续 AI 消息**`result-chat-list`)只有基础的展开/收起,缺少复制、换个方向、不像我、继续生成、播放。
3. **story-card 展开失效**:当用户触发过重新生成(`resultHasScriptReplies``true`)后,`<template v-if="!resultHasScriptReplies">` 会隐藏整个故事正文和底部展开按钮,导致点击展开无效果。
## 目标
- 每条 AI 回复消息卡片都拥有完整的功能按钮(展开/收起、复制、换个方向、不像我、继续生成、播放)
- 修复 story-card 展开失效的 bug
- 所有按钮功能正常可用
## 方案选择
采用 **方案 A:在现有单文件组件内修复 + 扩展**
- 不提取独立组件,保持现有文件结构
- 改动最小、风险低、不引入新文件
- 后续如有更复杂的差异化需求再升级
## 详细设计
### 1. 修复 story-card 展开失效
**根因**`ScriptView.vue` 第 192 行的条件包裹
```vue
<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>
```
`resultHasScriptReplies``true`(有 `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` 的视觉风格:
```css
.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` 样式