Files
happy-life-star/docs/superpowers/specs/2026-06-27-message-card-component-design.md
T
peanut f7dba6ba60 docs:新增 MessageCard 组件统一设计文档
- 提取 MessageCard.vue 独立组件
- 按 100 字阈值自动切换短消息/完整卡片模式
- story-card 和 result-chat-list 复用同一组件
2026-06-27 23:25:26 +08:00

159 lines
4.9 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: 提取 MessageCard 组件,统一所有 AI 消息卡片样式,按内容长度阈值(100 字)决定是否显示完整功能按钮
---
# MessageCard 组件统一设计
## 背景
在上一轮实现中,result-chat-list 中的 assistant 消息使用了 `.chat-bubble.system` 气泡样式,与 `story-card` 的卡片样式不一致。用户要求:
1. 所有 AI 回复消息卡片的样式、功能、布局、按钮等,都与第一次生成剧本的 `story-card` 完全一致
2. 内容 < 100 字的 assistant 消息:只显示消息内容,无功能按钮
3. 内容 ≥ 100 字的 assistant 消息:必须与 `story-card` 完全一致
## 目标
- 提取独立的 `MessageCard.vue` 组件
- story-card 和 result-chat-list 都复用该组件
- 按 100 字阈值自动切换显示模式
## 方案选择
采用 **方案 B:提取独立 MessageCard.vue 组件**
- 代码复用,维护性好
- 改动范围:新建 1 个组件 + 修改 ScriptView.vue
## 详细设计
### 1. 组件接口
**文件**`mini-program/src/components/MessageCard.vue`
**Props**
| Prop | 类型 | 必填 | 说明 |
|---|---|---|---|
| `content` | String | 是 | 消息/故事正文内容 |
| `title` | String | 否 | 卡片标题,默认 `'我的人生剧本'` |
| `tags` | Array | 否 | 标签列表 |
| `collapsed` | Boolean | 是 | 当前折叠状态 |
| `contentLength` | Number | 是 | 内容字数(用于阈值判断) |
| `isShortMessage` | Boolean | 是 | `contentLength < 100` 时为 true |
| `ttsIcon` | String | 否 | TTS 按钮图标(`▶``Ⅱ` |
| `ttsText` | String | 否 | TTS 按钮文字(`播放``暂停` |
**Events**
| 事件 | 说明 |
|---|---|
| `toggle-collapse` | 展开/收起 |
| `copy` | 复制内容 |
| `change-direction` | 换个方向 |
| `not-like-me` | 不像我 |
| `continue` | 继续生成 |
| `play-tts` | 播放 TTS |
### 2. 组件内部结构
**短消息(`isShortMessage = true`**
```vue
<view class="chat-bubble system">
<text>{{ content }}</text>
</view>
```
只显示纯文本气泡,无标题、无标签、无按钮。
**长消息(`isShortMessage = false`**
完整复用现有 `story-card` 的 HTML 结构:
- 标题(`.story-title`+ 标签(`.tag-row`
- 头部操作区:展开/收起按钮 + 复制按钮
- 正文:展开时用 scroll-view,收起时用 text
- 底部:展开全文/收起全文按钮
- 功能按钮组(2 列网格):换个方向、不像我、继续生成、播放
### 3. ScriptView.vue 中的使用
**替换现有 story-card**
```vue
<MessageCard
:content="displayedResultContent"
:title="currentResult?.title"
:tags="resultTags"
:collapsed="storyCollapsed"
:content-length="displayedResultContent.length"
:is-short-message="false"
:tts-icon="ttsActionIcon"
:tts-text="ttsActionText"
@toggle-collapse="toggleStoryCollapse"
@copy="copyResultContent"
@change-direction="changeDirection"
@not-like-me="notLikeMe"
@continue="continueInChat"
@play-tts="trackTtsClick"
/>
```
**替换 result-chat-list 中的 assistant 消息**
```vue
<view v-for="message in resultMessages" :key="message.id">
<MessageCard
v-if="isAssistantMessage(message)"
:content="message.content"
:collapsed="isMessageCollapsed(message)"
:content-length="message.content.length"
:is-short-message="message.content.length < 100"
:tts-icon="ttsPlayer.playing.value ? '' : ''"
:tts-text="ttsPlayer.playing.value ? '暂停' : '播放'"
@toggle-collapse="toggleMessageCollapse(message)"
@copy="copyMessageContent(message)"
@change-direction="changeDirection"
@not-like-me="notLikeMe"
@continue="continueInChat"
@play-tts="playMessageTts(message)"
/>
<view v-else class="chat-bubble user">
<text>{{ message.content }}</text>
<text class="bubble-time">{{ message.time }}</text>
</view>
</view>
```
### 4. 样式迁移
将以下 CSS 类从 `ScriptView.vue` 迁移到 `MessageCard.vue``<style scoped>` 中:
- `.story-card``.story-card.collapsed`
- `.story-head``.story-head-actions``.story-title-wrap`
- `.story-title``.tag-row``.tag`
- `.collapse-icon``.copy-card-btn``.collapse-row`
- `.collapse-chevron``.story-body``.story-body-scroll`
- `.result-actions``.action-btn`
`ScriptView.vue` 中删除这些已迁移的样式。
### 5. 边界情况
| 场景 | 行为 |
|---|---|
| content 刚好 100 字 | `isShortMessage = false`,显示完整卡片 |
| content 为空 | 显示空卡片(与 story-card 现有行为一致) |
| pending 中的消息 | 不使用 MessageCard,保持 thinking-dots 渲染 |
| user 消息 | 不使用 MessageCard,保持 `.chat-bubble.user` 气泡 |
## 修改范围
| 文件 | 操作 |
|---|---|
| `mini-program/src/components/MessageCard.vue` | 新建 |
| `mini-program/src/pages/main/ScriptView.vue` | 修改(模板 + 脚本 + 样式) |