---
author: Peanut
created_at: 2026-04-07
purpose: 定义小程序"创造未来"页面剧本卡片的 Markdown 渲染方案
---

# 小程序剧本卡片 Markdown 渲染设计

## 问题背景

小程序"创造未来"页面（ScriptView.vue）中，剧本卡片当前以纯文本形式显示内容：
- 摘要区域：`<text class="script-summary">{{ getScriptSummary(script) }}</text>`
- 完整内容：存储在 `script.plotJson.fullContent` 中

但后端返回的剧本数据是 **Markdown 格式**：
```markdown
### 人物小传
花生米曾有过光芒闪耀的"破土而出"时刻...

### 戏剧驱动力
- 主人公当下最想要的一件具体的东西是：成为武林高手。
- 为了得到它，他必须承受或放弃的是：原本正常的生活节奏...

#### 第一场：抉择
- **时间**：日
- **地点**：花生米家中
- **人物**：花生米
花生米（自言自语）："成为武林高手，这听起来多带劲啊..."
```

当前纯文本显示导致：
- 标题与普通文本无法区分
- 列表项没有项目符号
- 粗体等格式丢失
- 阅读体验差

## 设计方案

### 架构概述

```
┌─────────────────────────────────────────────────────────────┐
│                    ScriptView.vue                           │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  剧本卡片 (script-card)                              │    │
│  │  ┌─────────────────────────────────────────────┐    │    │
│  │  │  标题 /  persona                              │    │    │
│  │  ├─────────────────────────────────────────────┤    │    │
│  │  │  摘要区域 (Markdown 渲染 - 前 200 字符)           │    │    │
│  │  │  ### 人物小传                                 │    │    │
│  │  │  花生米曾有过光芒闪耀的...                    │    │    │
│  │  └─────────────────────────────────────────────┘    │    │
│  │  [路径映射 →]  (点击跳转详情页)                       │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘
                            │
                            ▼ 点击卡片
┌─────────────────────────────────────────────────────────────┐
│               ScriptDetailView.vue (新增)                    │
│  ┌─────────────────────────────────────────────────────┐    │
│  │  返回                     剧本标题                   │    │
│  ├─────────────────────────────────────────────────────┤    │
│  │                                                     │    │
│  │  完整 Markdown 内容渲染                               │    │
│  │  ### 人物小传                                       │    │
│  │  花生米曾有过...                                    │    │
│  │  ### 戏剧驱动力                                     │    │
│  │  - 主人公当下最想要...                              │    │
│  │  #### 第一场：抉择                                  │    │
│  │  - **时间**：日                                     │    │
│  │  ...                                                │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘
```

### 组件复用

**已有组件**：[`mini-program/src/components/Markdown.vue`](mini-program/src/components/Markdown.vue)

当前支持的 Markdown 格式：
- ✅ 分割线 `---`
- ✅ 四级标题 `#### `
- ✅ 列表项 `* ` / `- `
- ✅ 普通段落

**需要扩展支持**：
- ❌ 三级标题 `### `
- ❌ 粗体 `**text**`

### 文件结构

```
mini-program/src/
├── components/
│   └── Markdown.vue              # 扩展现有组件
├── pages/main/
│   ├── ScriptView.vue            # 修改：卡片摘要使用 Markdown
│   └── ScriptDetailView.vue      # 新增：剧本详情页
└── services/
    └── epicScript.js             # 现有服务，无需修改
```

## 实施细节

### 1. Markdown 组件扩展

**文件**：`mini-program/src/components/Markdown.vue`

**新增解析规则**：

```javascript
// 三级标题 ###
const h3Match = trimmed.match(/^###\s+(.+)/)
if (h3Match) {
  blocks.push({ type: 'h3', content: h3Match[1] })
  continue
}

// 粗体 **text** (在段落内容中处理)
// 由于小程序不支持富文本内的 HTML，粗体需要特殊处理
// 方案：将包含粗体的段落拆分为多个文本段
```

**模板新增**：
```vue
<!-- 三级标题 -->
<text v-else-if="block.type === 'h3'" class="markdown-h3">{{ block.content }}</text>
```

**样式**：
```css
.markdown-h3 {
  display: block;
  font-size: 30rpx;
  font-weight: 600;
  color: rgba(243, 232, 255, 0.95);
  margin: 20rpx 0 12rpx 0;
  line-height: 1.4;
}
```

### 2. ScriptView.vue 修改

**修改点 1**：导入 Markdown 组件
```javascript
import Markdown from '../../components/Markdown.vue'
```

**修改点 2**：摘要区域使用 Markdown 渲染
```vue
<!-- 原代码 -->
<text class="script-summary" lines="3">{{ getScriptSummary(script) }}</text>

<!-- 修改后 -->
<view class="script-summary">
  <Markdown :content="getScriptSummary(script)" />
</view>
```

**修改点 3**：添加点击跳转
```vue
<view class="script-card" @click="viewScriptDetail(script)">
  <!-- 卡片内容 -->
</view>
```

**修改点 4**：跳转方法
```javascript
const viewScriptDetail = (script) => {
  uni.navigateTo({
    url: `/pages/main/ScriptDetailView?id=${script.id}`
  })
}
```

### 3. ScriptDetailView.vue 新建

**文件**：`mini-program/src/pages/main/ScriptDetailView.vue`

**核心结构**：
```vue
<template>
  <view class="detail-view">
    <view class="detail-header">
      <text class="detail-title">{{ script.title }}</text>
      <text class="detail-theme">{{ script.theme }}</text>
    </view>
    
    <scroll-view class="detail-content" scroll-y>
      <Markdown :content="fullContent" />
    </scroll-view>
  </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useAppStore } from '../../stores/app.js'
import Markdown from '../../components/Markdown.vue'

const store = useAppStore()
const script = ref(null)
const fullContent = ref('')

onMounted(async () => {
  const pages = getCurrentPages()
  const currentPage = pages[pages.length - 1]
  const scriptId = currentPage.options.id
  
  // 从 store 获取剧本详情
  const targetScript = store.scripts.find(s => s.id === scriptId)
  script.value = targetScript
  
  // 获取完整内容
  if (targetScript?.plotJson?.fullContent) {
    fullContent.value = targetScript.plotJson.fullContent
  }
})
</script>
```

### 4. 摘要提取逻辑

**当前逻辑**：
```javascript
const getScriptSummary = (script) => {
  const text = script.summary || script.content || ''
  return text.replace(/\s+/g, ' ').trim()
}
```

**修改后**：
```javascript
const getScriptSummary = (script) => {
  // 优先使用 summary 字段
  if (script.summary) {
    return script.summary
  }
  
  // 从 fullContent 提取前 200 字符
  const fullContent = script.plotJson?.fullContent || ''
  if (fullContent) {
    // 提取内容，去掉 Markdown 符号
    return fullContent
      .split('\n')
      .filter(line => line.trim())
      .slice(0, 5)  // 取前 5 行
      .join('\n')
      .slice(0, 200) + '...'
  }
  
  return '暂无摘要'
}
```

## 验收标准

- [x] Markdown 组件支持三级标题 `###`
- [x] Markdown 组件支持粗体 `**text**`（如无法完美支持，降级为普通文本）
- [x] ScriptView.vue 卡片摘要使用 Markdown 渲染
- [x] 点击卡片可跳转到详情页查看完整内容
- [x] 详情页正确渲染完整 Markdown 格式
- [x] 样式与现有设计保持一致

## 注意事项

### 1. 粗体支持限制

微信小程序的 `<text>` 组件不支持富文本内的局部样式。

**解决方案**：
- 方案 A：使用正则将 `**text**` 拆分为多个 `<text>` 组件（复杂）
- 方案 B：降级处理，粗体标记移除但保留文字（简单）

**推荐**：先实现方案 B，如效果不佳再考虑方案 A。

### 2. 长内容加载

剧本完整内容可能较长（2000+ 字符），详情页使用 `<scroll-view>` 确保可滚动浏览。

### 3. 数据获取

- 剧本数据已通过 `store.fetchScripts()` 加载到 store
- 详情页从 store 根据 ID 获取，无需额外 API 调用

## 参考文档

- [uni-app 页面跳转](https://uniapp.dcloud.net.cn/api/router.html)
- [uni-app scroll-view](https://uniapp.dcloud.net.cn/component/scroll-view.html)
- 已有 Markdown 组件：`mini-program/src/components/Markdown.vue`
