Files
happy-life-star/docs/superpowers/plans/2026-06-27-ai-message-card-buttons.md
T

14 KiB
Raw Blame History

author, created_at, purpose
author created_at purpose
claude 2026-06-27 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 行)。

修改前:

<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>

修改后:

<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: 提交代码
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 行),添加复制消息内容的方法:

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 的方法:

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 行),在方法开头添加埋点代码:

修改前:

const toggleMessageCollapse = (message) => {
  collapsedMessageIds.value[message.id] = !isMessageCollapsed(message)
}

修改后:

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: 提交代码
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 行),在消息内容和展开/收起按钮之后、时间戳之前,添加功能按钮组。

修改前:

<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>

修改后:

<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: 提交代码
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 样式附近,添加按钮组样式:

.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: 提交代码
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 返回空内容)
  • 点击「复制」按钮
  • 预期: 显示「暂无可复制内容」提示

场景 2pending 状态的 assistant 消息

  • 生成故事后,快速点击「继续生成」
  • 观察正在加载的 assistant 消息(pending 状态)
  • 预期: pending 消息不显示功能按钮组

场景 3user 消息

  • 查看用户发送的消息
  • 预期: 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: 最终提交(如有修改)

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

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

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

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

  • Step 7: 创建 Pull Request(可选)

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

git push origin HEAD

然后在代码托管平台创建 PR,标题:

feat: 统一 AI 消息卡片功能按钮并修复 story-card 展开失效

PR 描述包含:

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