---
author: claude
created_at: 2026-06-27
purpose: AI 消息卡片功能按钮统一实现计划
---

# AI 消息卡片功能按钮统一实现计划

> **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:** 统一小程序实现心愿页面中所有 AI 消息卡片的功能按钮，并修复 story-card 展开失效 bug

**Architecture:** 在现有单文件组件 `ScriptView.vue` 内修复 + 扩展，不提取独立组件，保持现有文件结构

**Tech Stack:** Vue 3, UniApp, 微信小程序

---

## 文件结构

**修改：**
- `mini-program/src/pages/main/ScriptView.vue` - 主页面组件（模板 + 脚本 + 样式）

---

### Task 1: 修复 story-card 展开失效 bug

**Files:**
- Modify: `mini-program/src/pages/main/ScriptView.vue:192-210`

- [ ] **Step 1: 移除 resultHasScriptReplies 条件包裹**

打开 `mini-program/src/pages/main/ScriptView.vue`，找到第 192 行的 `<template v-if="!resultHasScriptReplies">`，删除这个条件包裹标签和对应的 `</template>` 闭合标签（第 210 行）。

修改前：
```vue
<template v-if="!resultHasScriptReplies">
  <scroll-view
    v-if="storyCollapsed"
    class="story-body-scroll"
    scroll-y
    :enhanced="true"
    :show-scrollbar="true"
  >
    <text class="story-body" :selectable="true" :user-select="true">{{ displayedResultContent }}</text>
  </scroll-view>
  <text v-else class="story-body" :selectable="true" :user-select="true">{{ displayedResultContent }}</text>
  <view class="collapse-row" @click="toggleStoryCollapse">
    <text class="collapse-row-text">{{ storyCollapsed ? '展开全文' : '收起全文' }}</text>
    <view class="collapse-chevron" :class="{ down: storyCollapsed }">
      <view></view>
      <view></view>
    </view>
  </view>
</template>
```

修改后：
```vue
<scroll-view
  v-if="storyCollapsed"
  class="story-body-scroll"
  scroll-y
  :enhanced="true"
  :show-scrollbar="true"
>
  <text class="story-body" :selectable="true" :user-select="true">{{ displayedResultContent }}</text>
</scroll-view>
<text v-else class="story-body" :selectable="true" :user-select="true">{{ displayedResultContent }}</text>
<view class="collapse-row" @click="toggleStoryCollapse">
  <text class="collapse-row-text">{{ storyCollapsed ? '展开全文' : '收起全文' }}</text>
  <view class="collapse-chevron" :class="{ down: storyCollapsed }">
    <view></view>
    <view></view>
  </view>
</view>
```

- [ ] **Step 2: 验证修复**

在微信开发者工具中编译运行，进入「实现心愿」页面：
1. 输入心愿并生成故事
2. 点击「继续生成」创建 script 类型消息
3. 点击 story-card 的展开/收起按钮，验证故事正文能正确展开和收起
4. 确认控制台无报错

- [ ] **Step 3: 提交代码**

```bash
git add mini-program/src/pages/main/ScriptView.vue
git commit -m "fix: 修复 story-card 展开失效 bug

移除 resultHasScriptReplies 条件包裹，让故事正文始终由 storyCollapsed 控制展开/收起"
```

---

### Task 2: 添加新方法支持消息卡片功能

**Files:**
- Modify: `mini-program/src/pages/main/ScriptView.vue` (script 部分)

- [ ] **Step 1: 添加 copyMessageContent 方法**

在 `toggleMessageCollapse` 方法之后（约第 450 行），添加复制消息内容的方法：

```javascript
const copyMessageContent = (message) => {
  const content = message?.content || ''
  if (!content.trim()) {
    uni.showToast({ title: '暂无可复制内容', icon: 'none' })
    return
  }
  uni.setClipboardData({
    data: content,
    success: () => {
      uni.showToast({ title: '已复制', icon: 'success' })
    }
  })
  analytics.track('script_message_copy_click', {
    message_id: message?.id || '',
    content_length: content.length
  }, { eventType: 'script', pagePath })
}
```

- [ ] **Step 2: 添加 playMessageTts 方法**

在 `copyMessageContent` 方法之后，添加播放 TTS 的方法：

```javascript
const playMessageTts = (message) => {
  const scriptId = currentResult.value?.id || ''
  ttsPlayer.playSource(scriptId)
  analytics.track('script_message_tts_click', {
    message_id: message?.id || '',
    script_id: scriptId
  }, { eventType: 'script', pagePath })
}
```

- [ ] **Step 3: 修改 toggleMessageCollapse 方法添加埋点**

找到 `toggleMessageCollapse` 方法（约第 442-450 行），在方法开头添加埋点代码：

修改前：
```javascript
const toggleMessageCollapse = (message) => {
  collapsedMessageIds.value[message.id] = !isMessageCollapsed(message)
}
```

修改后：
```javascript
const toggleMessageCollapse = (message) => {
  collapsedMessageIds.value[message.id] = !isMessageCollapsed(message)
  analytics.track('script_message_collapse_toggle', {
    message_id: message?.id || '',
    collapsed: collapsedMessageIds.value[message.id]
  }, { eventType: 'script', pagePath })
}
```

- [ ] **Step 4: 验证方法添加**

在微信开发者工具中编译运行，确认控制台无语法错误。新方法暂时不会被调用，后续任务会在模板中使用。

- [ ] **Step 5: 提交代码**

```bash
git add mini-program/src/pages/main/ScriptView.vue
git commit -m "feat: 添加消息卡片功能方法

- copyMessageContent: 复制消息内容到剪贴板
- playMessageTts: 播放故事 TTS 音频
- toggleMessageCollapse: 添加展开/收起埋点"
```

---

### Task 3: 在 result-chat-list 中添加功能按钮组

**Files:**
- Modify: `mini-program/src/pages/main/ScriptView.vue:245-270`

- [ ] **Step 1: 在 assistant 消息中添加功能按钮组**

找到 `result-chat-list` 部分（约第 245-270 行），在消息内容和展开/收起按钮之后、时间戳之前，添加功能按钮组。

修改前：
```vue
<view
  v-for="(message, index) in resultMessages"
  :key="message.id"
  class="result-chat-list"
>
  <view
    v-if="isAssistantMessage(message)"
    class="chat-bubble assistant"
  >
    <text class="message-content">{{ getMessageContent(message) }}</text>
    <view class="message-toggle" @click="toggleMessageCollapse(message)">
      <text>{{ isMessageCollapsed(message) ? '展开全文' : '收起全文' }}</text>
      <view class="collapse-chevron" :class="{ down: isMessageCollapsed(message) }">
        <view></view>
        <view></view>
      </view>
    </view>
    <text class="message-time">{{ formatMessageTime(message.createdAt) }}</text>
  </view>
  <!-- user message -->
</view>
```

修改后：
```vue
<view
  v-for="(message, index) in resultMessages"
  :key="message.id"
  class="result-chat-list"
>
  <view
    v-if="isAssistantMessage(message)"
    class="chat-bubble assistant"
  >
    <text class="message-content">{{ getMessageContent(message) }}</text>
    <view class="message-toggle" @click="toggleMessageCollapse(message)">
      <text>{{ isMessageCollapsed(message) ? '展开全文' : '收起全文' }}</text>
      <view class="collapse-chevron" :class="{ down: isMessageCollapsed(message) }">
        <view></view>
        <view></view>
      </view>
    </view>
    <view class="message-actions">
      <view class="action-btn" @click="copyMessageContent(message)">
        <text>复制</text>
      </view>
      <view class="action-btn" @click="changeDirection">
        <text>换个方向</text>
      </view>
      <view class="action-btn" @click="notLikeMe">
        <text>不像我</text>
      </view>
      <view class="action-btn" @click="continueInChat">
        <text>继续生成</text>
      </view>
      <view class="action-btn primary" @click="playMessageTts(message)">
        <text>▶ 播放</text>
      </view>
    </view>
    <text class="message-time">{{ formatMessageTime(message.createdAt) }}</text>
  </view>
  <!-- user message -->
</view>
```

**说明：**
- 按钮组使用 `.message-actions` 容器，2 列网格布局
- 复制、换个方向、不像我、继续生成使用 `.action-btn` 样式
- 播放按钮使用 `.action-btn.primary` 样式（主色调突出）
- 所有按钮都调用 Task 2 中定义的方法或复用现有方法

- [ ] **Step 2: 验证按钮组显示**

在微信开发者工具中编译运行：
1. 进入「实现心愿」页面，生成故事
2. 点击「继续生成」创建 assistant 消息
3. 验证每条 assistant 消息下方显示 5 个功能按钮（复制、换个方向、不像我、继续生成、播放）
4. 验证按钮布局为 2 列网格

- [ ] **Step 3: 验证按钮功能**

逐个测试按钮功能：
1. **复制**：点击后应复制消息内容，显示「已复制」提示
2. **换个方向**：点击后应进入「换方向」修订确认流程
3. **不像我**：点击后应进入「不像我」修订确认流程
4. **继续生成**：点击后应收起故事并聚焦输入框
5. **播放**：点击后应播放故事 TTS 音频

确认控制台无报错，所有功能正常。

- [ ] **Step 4: 提交代码**

```bash
git add mini-program/src/pages/main/ScriptView.vue
git commit -m "feat: 在 result-chat-list 中添加功能按钮组

为每条 assistant 消息添加完整功能按钮：
- 复制：复制消息内容到剪贴板
- 换个方向：进入换方向修订确认
- 不像我：进入不像我修订确认
- 继续生成：收起故事并聚焦输入框
- 播放：播放故事 TTS 音频"
```

---

### Task 4: 添加消息按钮组样式

**Files:**
- Modify: `mini-program/src/pages/main/ScriptView.vue` (style 部分)

- [ ] **Step 1: 添加 .message-actions 样式**

在 `<style scoped>` 部分（约第 1500 行之后），找到 `.message-toggle` 样式附近，添加按钮组样式：

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

.message-actions .action-btn {
  padding: 16rpx 24rpx;
  background: rgba(255, 255, 255, 0.08);
  border: 2rpx solid rgba(255, 255, 255, 0.15);
  border-radius: 16rpx;
  color: #e0e0e0;
  font-size: 24rpx;
  text-align: center;
  transition: all 0.2s;
}

.message-actions .action-btn:active {
  background: rgba(255, 255, 255, 0.12);
  transform: scale(0.98);
}

.message-actions .action-btn.primary {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-color: transparent;
  color: #ffffff;
  font-weight: 500;
}

.message-actions .action-btn.primary:active {
  opacity: 0.85;
}
```

- [ ] **Step 2: 验证样式效果**

在微信开发者工具中编译运行：
1. 进入「实现心愿」页面，生成故事
2. 点击「继续生成」创建 assistant 消息
3. 验证按钮样式：
   - 按钮组为 2 列网格布局
   - 普通按钮为半透明白色背景，圆角边框
   - 播放按钮为主色调渐变（紫色）
   - 点击时有缩放反馈效果
4. 验证按钮在不同屏幕尺寸下的响应式表现

- [ ] **Step 3: 提交代码**

```bash
git add mini-program/src/pages/main/ScriptView.vue
git commit -m "style: 添加消息按钮组样式

- .message-actions: 2 列网格布局，间距 16rpx
- .action-btn: 半透明白色背景，圆角边框，点击反馈
- .action-btn.primary: 主色调渐变（紫色），白色文字"
```

---

### Task 5: 最终验证和边界情况测试

**Files:**
- 无需修改文件，仅做验证

- [ ] **Step 1: 测试 story-card 展开/收起**

在微信开发者工具中编译运行：
1. 进入「实现心愿」页面
2. 输入心愿并生成故事
3. 点击 story-card 的「展开全文」按钮，验证故事正文展开
4. 点击「收起全文」按钮，验证故事正文收起
5. 点击「继续生成」创建 script 类型消息
6. 再次点击 story-card 的展开/收起按钮，验证功能正常（之前会失效）

**预期结果：** 所有展开/收起操作正常工作

- [ ] **Step 2: 测试 assistant 消息功能按钮**

继续在上一步的基础上：
1. 验证每条 assistant 消息下方显示 5 个功能按钮
2. 点击「复制」按钮，验证复制成功提示
3. 点击「换个方向」按钮，验证进入修订确认流程
4. 点击「不像我」按钮，验证进入修订确认流程
5. 点击「继续生成」按钮，验证故事收起且输入框获得焦点
6. 点击「播放」按钮，验证 TTS 音频播放

**预期结果：** 所有按钮功能正常

- [ ] **Step 3: 测试边界情况**

测试以下边界场景：

**场景 1：空内容的 assistant 消息**
- 手动构造一条空内容的 assistant 消息（或等待 AI 返回空内容）
- 点击「复制」按钮
- **预期：** 显示「暂无可复制内容」提示

**场景 2：pending 状态的 assistant 消息**
- 生成故事后，快速点击「继续生成」
- 观察正在加载的 assistant 消息（pending 状态）
- **预期：** pending 消息不显示功能按钮组

**场景 3：user 消息**
- 查看用户发送的消息
- **预期：** user 消息不显示功能按钮组

**场景 4：无 currentResult 时的播放**
- 如果可能，测试在未生成故事时点击播放按钮
- **预期：** 按钮仍可点击，TTS 播放器内部处理空 id

- [ ] **Step 4: 验证埋点**

打开微信开发者工具的控制台，查看埋点日志：
1. 点击 assistant 消息的展开/收起按钮，验证 `script_message_collapse_toggle` 埋点
2. 点击「复制」按钮，验证 `script_message_copy_click` 埋点
3. 点击「播放」按钮，验证 `script_message_tts_click` 埋点

**预期结果：** 所有埋点正确触发，包含正确的参数

- [ ] **Step 5: 检查控制台错误**

在整个测试过程中，持续关注微信开发者工具的控制台：
- 确认无 Vue 警告
- 确认无 JavaScript 错误
- 确认无网络请求错误

**预期结果：** 控制台干净，无任何错误

- [ ] **Step 6: 最终提交（如有修改）**

如果在前面的测试中发现了需要修复的问题，修复后提交：

```bash
git add mini-program/src/pages/main/ScriptView.vue
git commit -m "fix: 修复最终验证中发现的问题

[描述修复的具体问题]"
```

如果测试全部通过，无需额外提交。

- [ ] **Step 7: 创建 Pull Request（可选）**

如果项目使用 PR 流程，创建 PR 合并这些更改：

```bash
git push origin HEAD
```

然后在代码托管平台创建 PR，标题：
```
feat: 统一 AI 消息卡片功能按钮并修复 story-card 展开失效
```

PR 描述包含：
- 修复 story-card 展开失效 bug
- 为每条 assistant 消息添加完整功能按钮组
- 添加相应的样式和埋点
- 所有功能已通过测试
