模板变量 Markdown 导出配置/.md 格式

巴克励步

发布于:2026-04-08

👋
应用默认每个 URL 都可以转换为.md 格式,如:
https://dev.baklib.cn/faqs/a121
则默认有个路径为:path 和 url 的区别?

本文档面向开发者,说明如何通过 `Page::ToMarkdown` 模块将页面模板变量导出为 Markdown 格式。

## 功能概述

`Page::ToMarkdown` 是一个 Rails Concern 模块,用于将页面的模板变量按配置转换为 Markdown 格式。主要应用场景包括:

- LLM 训练数据导出
- 内容备份与迁移
- 文档生成

## 配置方式

### 1. 模板 Schema 配置

在模板 JSON Schema 中,通过添加 `to_markdown: true` 标记需要导出的变量:

```json
{
  "id": "content",
  "type": "richtext",
  "label": "正文内容",
  "to_markdown": true
}
```

### 2. 批量配置示例

```json
{
  "settings": [
    {
      "id": "title",
      "type": "text",
      "label": "标题",
      "to_markdown": true
    },
    {
      "id": "summary",
      "type": "textarea",
      "label": "摘要",
      "to_markdown": true
    },
    {
      "id": "body",
      "type": "richtext",
      "label": "正文",
      "to_markdown": true
    },
    {
      "id": "cover_image",
      "type": "image_picker",
      "label": "封面图",
      "to_markdown": true
    }
  ]
}
```

## 支持的字段类型映射

| 类型分类 | 具体类型 | Markdown 输出行为 |
|---------|---------|------------------|
| **富文本类型** (`RICH_TYPES`) | `richtext`, `html` | 通过 `FragmentValue.to_markdown` 转换 |
| **纯文本类型** (`PLAIN_TEXT_TYPES`) | `text`, `textarea`, `paragraph` | 直接输出字符串 |
| **代码类型** (`CODE_TYPES`) | `code` | 包裹为代码块,支持 `language` 指定语法 |
| **选项类型** (`CHOICE_TYPES`) | `select`, `radio`, `checkbox`, `link` | 直接输出值 |
| **简单值类型** (`SIMPLE_VALUE_TYPES`) | `number`, `range`, `date`, `color`, `font_picker`, `color_background` | 直接输出字符串 |
| **资源选择器** (`PICKER_TYPES`) | `image_picker`, `file_picker`, `video_picker`, `dam_picker` | 生成 20 分钟有效期的前端访问地址 |
| **标签选择器** (`TAG_PICKER_TYPE`) | `tag_picker` | 输出标签名称列表 |

## 输出格式

### 标准段落格式

每个启用了 `to_markdown: true` 的变量输出为:

```markdown
## {label}

{转换后的内容}

```

其中 `label` 优先取 `setting["label"]`,否则使用 `id.humanize`。

### 各类型详细输出示例

#### 富文本类型

输入 HTML 内容:
```html
<p>这是一段<strong>加粗</strong>的文本。</p>
```

输出:
```markdown
## 正文

这是一段**加粗**的文本。
```

#### 代码类型

Schema 配置:
```json
{
  "id": "script",
  "type": "code",
  "label": "脚本代码",
  "language": "javascript",
  "to_markdown": true
}
```

输出:
```markdown
## 脚本代码

```javascript
const x = 1;
```

```

#### 图片选择器

输出 Markdown 图片语法:
```markdown
## 封面图

![图片名称](https://portal.example.com/signed-url?expires=...)
```

#### 文件/视频选择器

仅输出 URL 字符串(无 Markdown 包裹):
```
## 附件

https://portal.example.com/signed-url?expires=...
```

#### 标签选择器

根据标签 IID 输出名称列表:
```markdown
## 标签

技术, 文档, 教程
```

## 资源链接有效期配置

资源选择器生成的 URL 有效期默认为 20 分钟,可通过修改常量调整:

```ruby
# app/models/page/to_markdown.rb
PORTAL_URL_EXPIRES_IN = 20.minutes
```

## 边界情况处理

### 自动 HTML 检测

对于未明确分类的类型,如果值匹配 HTML 标签正则 `/<[a-z][\s\S]*>/i`,自动使用 `FragmentValue.to_markdown` 转换。

### 空值过滤规则

- 变量值为空(`blank?`)时跳过该段落
- 转换后内容为空时跳过该段落
- `label` 为空时使用 `id.humanize` 作为标题

## 依赖要求

使用该模块的模型需要具备以下方法/关联:

| 方法/关联 | 说明 |
|----------|------|
| `templated_page` | 返回页面的模板实例 |
| `templated_page.template` | 模板配置对象 |
| `templated_page.translated_template_settings_with_value` | 返回含当前值的模板设置项数组 |
| `organization` | 返回页面所属组织 |
| `site` | 返回页面所属站点(用于标签和资源 URL 生成) |

## 调试方法

```ruby
page = Page.find(id)

# 查看完整 Markdown 输出
puts page.to_markdown

# 检查模板设置
puts page.templated_page.translated_template_settings_with_value.select { |s| s["to_markdown"] }.inspect
```

## 与 FragmentValue 的关系

富文本和 HTML 类型的转换依赖于 `FragmentValue.to_markdown` 方法,该方法:

- 将 BKE 编辑器 JSON/HTML 转换为标准 Markdown
- 处理 `bke:` 协议扩展语法
- 支持 `link-card`、`callout` 等自定义组件的 Markdown 表示

详见 [BKE Markdown 协议文档](bke/protocols/markdown.md)。

## 注意事项

1. **资源 URL 有效期**:导出的资源链接(图片、文件、视频)有过期时间,不适合长期存储
2. **标签解析依赖站点**:标签选择器根据当前站点作用域解析标签名称
3. **性能考虑**:大批量导出时建议异步处理(如使用 Rails Job)
4. **扩展类型处理**:新增字段类型需要在 `value_to_markdown_body` 方法中添加对应处理逻辑
提交反馈