Skip to content

Obsidian 自动化 Cookbook

将 QuickAdd(快速输入)、Templater(模板引擎)和 Dataview(数据查询)三大插件组合使用,可以实现强大的自动化工作流。本文提供 12 个实战配方,覆盖日常知识管理的核心场景。

三件套各自职责

插件核心职责在自动化中的角色
QuickAdd快速捕获输入入口:一键创建笔记、快速填写属性
Templater模板渲染与脚本引擎:动态生成内容、执行逻辑
Dataview数据查询与展示输出:自动汇总、统计、仪表板

配方 1:一键创建读书笔记

目标:输入书名,自动创建包含标准结构的读书笔记。

Templater 模板

markdown
<%* 
// templates/book-note.md
const title = await tp.system.prompt("书名");
const author = await tp.system.prompt("作者");
const category = await tp.system.suggester(
  ["技术", "商业", "文学", "心理学", "历史", "其他"],
  ["技术", "商业", "文学", "心理学", "历史", "其他"]
);
-%>
---
title: "《<% title %>》"
author: "<% author %>"
category: "<% category %>"
status: to-read
rating: 
started_date: 
finished_date: 
total_pages: 
current_page: 0
tags: [book, <% category %>]
created: <% tp.date.now("YYYY-MM-DD") %>
---

# 《<% title %>》

> 作者: <% author %>

## 📖 基本信息

| 项目 | 内容 |
|------|------|
| 状态 | 📋 待阅读 |
| 分类 | <% category %> |
| 开始日期 | — |
| 完成日期 | — |
| 当前页数 | 0 |

## 💡 核心观点

- 

## 📝 章节笔记

### 第一章

### 第二章

## ✍️ 读后感

## 🔗 相关书籍

```dataview
LIST
FROM "books"
WHERE author = "<% author %>" AND file.name != this.file.name
SORT rating DESC

### QuickAdd 配置

1. 创建 QuickAdd Capture → 选择模板文件
2. 设置文件名格式:`books/&#123;&#123;DATE:YYYY-MM-DD&#125;&#125;-&#123;&#123;VALUE&#125;&#125;`
3. 设置保存路径:`books/`

## 配方 2:每日晨间日记自动化

**目标**:每天早上一键生成包含天气、待办、回顾的晨间日记。

### Templater 模板

```markdown
<%* 
// templates/morning-journal.md
const weather = await tp.system.suggester(
  ["☀️ 晴天", "⛅ 多云", "🌧️ 雨天", "❄️ 雪天", "🌫️ 雾天"],
  ["sunny", "cloudy", "rainy", "snowy", "foggy"]
);
const mood = await tp.system.suggester(
  ["😀 很好", "🙂 不错", "😐 一般", "😕 不好", "😢 糟糕"],
  [5, 4, 3, 2, 1]
);
-%>
---
type: daily-journal
date: <% tp.date.now("YYYY-MM-DD") %>
weather: <% weather %>
mood: <% mood %>
tags: [journal, morning]
---

# 📅 <% tp.date.now("YYYY年MM月DD日 dddd") %>

## 🌤️ 今日概况

- 天气:<% weather %>
- 心情:<% mood %>

## 🎯 今日目标

```dataviewjs
// 自动拉取今日待办
const today = dv.date("today");
const tasks = dv.pages('"tasks"')
  .file.tasks
  .where(t => !t.completed)
  .where(t => t.due == today || t.text.includes(today.toFormat("yyyy-MM-dd")))
  .limit(5);

if (tasks.length > 0) {
  dv.taskList(tasks, false);
} else {
  dv.paragraph("今日暂无待办任务,享受轻松的一天!");
}

📝 晨间反思

昨日回顾

今日感恩

今日重点

📊 本周数据

dataviewjs
const weekStart = dv.date("today").minus({ days: dv.date("today").weekday - 1 });
const weekNotes = dv.pages('"daily"')
  .where(p => p.file.day >= weekStart && p.file.day <= dv.date("today"))
  .sort(p => p.file.day);

dv.table(
  ["日期", "心情", "天气", "笔记数"],
  weekNotes.map(p => [
    p.file.link,
    p.mood ? "⭐".repeat(p.mood) : "—",
    p.weather || "—",
    p.file.tasks.length
  ])
);

🔗 昨日日记

dataviewjs
const yesterday = dv.date("today").minus({ days: 1 });
const yd = dv.pages('"daily"')
  .where(p => p.file.day == yesterday);

if (yd.length > 0) {
  dv.paragraph("📝 " + yd[0].file.link);
} else {
  dv.paragraph("昨日无日记记录");
}

## 配方 3:会议记录自动生成

**目标**:输入会议主题和参会人,自动生成会议记录模板并创建关联任务。

### QuickAdd Macro 模板

```markdown
<%*
// templates/meeting-note.md
const topic = await tp.system.prompt("会议主题");
const attendees = await tp.system.prompt("参会人员(逗号分隔)");
const attendeeList = attendees.split(",").map(a => a.trim());

// 创建会议笔记
const fileName = `会议-${tp.date.now("YYYYMMDD-HHmm")}-${topic}`;
await tp.file.rename(fileName);
await tp.file.move(`meetings/${fileName}`);
-%>
---
type: meeting
topic: "<% topic %>"
attendees: [<% attendeeList.map(a => `"${a}"`).join(", ") %>]
date: <% tp.date.now("YYYY-MM-DD") %>
time: <% tp.date.now("HH:mm") %>
status: draft
tags: [meeting]
---

# 📋 会议:<% topic %>

## 📝 基本信息

| 项目 | 内容 |
|------|------|
| 日期 | <% tp.date.now("YYYY-MM-DD") %> |
| 时间 | <% tp.date.now("HH:mm") %> |
| 参会人 | <% attendees %> |
| 记录人 | [[<% tp.frontmatter.author || "我" %>] |

## 📋 议程

1. 

## 💬 讨论内容

### 议题 1

**讨论要点:**
- 

**决议:**
- 

### 议题 2

## ✅ 行动项

- [ ] 
- [ ] 
- [ ] 

## 📎 附件

- 

## 🔗 相关项目

```dataview
LIST
FROM "projects"
WHERE contains(file.outlinks, this.file.link)
SORT file.name

📤 会后任务

dataviewjs
// 自动从会议笔记中提取任务并汇总
const tasks = dv.current().file.tasks;
if (tasks.length > 0) {
  dv.header(3, "📋 本次会议行动项");
  dv.taskList(tasks.where(t => !t.completed), false);
  
  const completed = tasks.where(t => t.completed);
  if (completed.length > 0) {
    dv.header(4, "✅ 已完成");
    dv.taskList(completed, false);
  }
}

## 配方 4:项目状态看板自动更新

**目标**:Dataview 自动从项目笔记中提取状态,生成看板式概览。

```dataviewjs
// project-dashboard.md
const projects = dv.pages('"projects"')
  .where(p => p.status);

const statuses = {
  "🟢 进行中 (active)": projects.where(p => p.status === "active"),
  "🟡 暂停 (paused)": projects.where(p => p.status === "paused"),
  "🔵 规划中 (planning)": projects.where(p => p.status === "planning"),
  "✅ 已完成 (done)": projects.where(p => p.status === "done"),
  "📦 已归档 (archived)": projects.where(p => p.status === "archived")
};

dv.header(2, "📊 项目看板");

for (let [label, group] of Object.entries(statuses)) {
  if (group.length === 0) continue;
  dv.header(3, `${label} — ${group.length} 个项目`);
  
  dv.table(
    ["项目", "优先级", "截止日期", "进度", "负责"],
    group.sort(p => p.priority || 99).map(p => {
      const daysLeft = p.deadline 
        ? Math.floor((dv.date(p.deadline) - dv.date("today")).days) 
        : null;
      return [
        p.file.link,
        p.priority ? `P${p.priority}` : "—",
        p.deadline ? `${p.deadline} (${daysLeft}天)` : "—",
        p.progress ? `${p.progress}%` : "—",
        p.assignee || "—"
      ];
    })
  );
}

// 统计概览
dv.header(3, "📈 统计概览");
dv.table(
  ["指标", "数值"],
  [
    ["项目总数", projects.length],
    ["进行中", projects.where(p => p.status === "active").length],
    ["本月到期", projects.where(p => p.deadline && dv.date(p.deadline).month == dv.date("today").month).length],
    ["已逾期", projects.where(p => p.deadline && dv.date(p.deadline) < dv.date("today") && p.status !== "done").length]
  ]
);

配方 5:周报自动生成

目标:一键生成本周工作周报,包含任务完成情况、新增笔记和项目进展。

Templater 模板

markdown
<%*
// templates/weekly-report.md
const today = tp.date.now("YYYY-MM-DD");
const weekNum = tp.date.now("ww");
await tp.file.rename(`周报-W${weekNum}-${today}`);
await tp.file.move(`reports/weekly/${tp.file.title}`);
-%>
---
type: weekly-report
week: <% tp.date.now("ww") %>
date: <% today %>
period: <% tp.date.now("YYYY-[W]ww") %>
tags: [report, weekly]
---

# 📋 周报 — <% tp.date.now("YYYY年MM月DD日") %> (W<% weekNum %>)

## 📊 本周概览

```dataviewjs
const today = dv.date("today");
const weekStart = today.minus({ days: today.weekday - 1 });
const weekEnd = weekStart.plus({ days: 6 });

// 新增笔记
const newNotes = dv.pages()
  .where(p => p.file.ctime >= weekStart && p.file.ctime <= weekEnd.plus({days: 1}))
  .where(p => !p.file.path.startsWith("Templates"))
  .where(p => !p.file.path.startsWith("reports"));

// 完成任务
const completedTasks = dv.pages()
  .file.tasks
  .where(t => t.completed)
  .where(t => t.completion >= weekStart && t.completion <= weekEnd.plus({days: 1}));

// 未完成任务
const pendingTasks = dv.pages()
  .file.tasks
  .where(t => !t.completed);

dv.table(
  ["📊 指标", "数值"],
  [
    ["📝 新增笔记", newNotes.length],
    ["✅ 完成任务", completedTasks.length],
    ["📋 待办任务", pendingTasks.length],
    ["📁 活跃项目", dv.pages('"projects"').where(p => p.status == "active").length]
  ]
);

✅ 本周完成任务

dataviewjs
const today = dv.date("today");
const weekStart = today.minus({ days: today.weekday - 1 });
const weekEnd = weekStart.plus({ days: 6 });

const tasks = dv.pages()
  .file.tasks
  .where(t => t.completed)
  .where(t => t.completion >= weekStart && t.completion <= weekEnd.plus({days: 1}));

if (tasks.length > 0) {
  dv.taskList(tasks, true);
} else {
  dv.paragraph("本周无已完成任务");
}

📝 本周新增笔记

dataviewjs
const today = dv.date("today");
const weekStart = today.minus({ days: today.weekday - 1 });
const weekEnd = weekStart.plus({ days: 6 });

const notes = dv.pages()
  .where(p => p.file.ctime >= weekStart && p.file.ctime <= weekEnd.plus({days: 1}))
  .where(p => !p.file.path.startsWith("Templates"))
  .where(p => !p.file.path.startsWith("reports"))
  .sort(p => p.file.ctime, 'desc');

dv.table(
  ["笔记", "创建时间", "标签"],
  notes.map(p => [
    p.file.link,
    p.file.ctime.toFormat("MM-dd HH:mm"),
    p.tags ? p.tags.join(", ") : "—"
  ])
);

📋 下周计划

  • [ ]
  • [ ]
  • [ ]

💡 反思与总结

本周亮点

待改进

下周重点


## 配方 6-12:更多自动化配方

### 配方 6:自动标签建议

```dataviewjs
// 根据笔记内容自动推荐标签
const content = dv.current().file.content;
const keywords = {
  "技术": ["代码", "编程", "API", "框架", "开发", "bug", "部署"],
  "学习": ["课程", "教程", "学习", "笔记", "复习", "考试"],
  "工作": ["会议", "项目", "汇报", "截止", "客户", "需求"],
  "生活": ["旅行", "美食", "运动", "健康", "家庭"]
};

const suggestions = [];
for (let [tag, words] of Object.entries(keywords)) {
  const matches = words.filter(w => content.includes(w));
  if (matches.length > 0) {
    suggestions.push({ tag, count: matches.length, words: matches });
  }
}

if (suggestions.length > 0) {
  dv.header(4, "🏷️ 建议标签");
  dv.table(
    ["标签", "匹配关键词数", "关键词"],
    suggestions.sort((a, b) => b.count - a.count).map(s => 
      [`#${s.tag}`, s.count, s.words.join(", ")]
    )
  );
}

配方 7:过期笔记提醒

dataviewjs
// 检测超过 90 天未修改的笔记
const threshold = dv.date("today").minus({ days: 90 });
const stale = dv.pages()
  .where(p => p.file.mtime < threshold)
  .where(p => !p.file.path.startsWith("Templates"))
  .where(p => !p.file.path.startsWith("Archive"))
  .sort(p => p.file.mtime)
  .limit(20);

if (stale.length > 0) {
  dv.header(3, `⚠️ ${stale.length} 篇笔记超过 90 天未更新`);
  dv.table(
    ["笔记", "最后修改", "天数"],
    stale.map(p => [
      p.file.link,
      p.file.mtime.toFormat("yyyy-MM-dd"),
      Math.floor((dv.date("today") - dv.date(p.file.mtime)).days)
    ])
  );
}

配方 8:知识图谱密度分析

dataviewjs
// 分析笔记的链接密度
const pages = dv.pages()
  .where(p => !p.file.path.startsWith("Templates"))
  .where(p => !p.file.path.startsWith("Archive"));

const stats = pages.map(p => ({
  name: p.file.name,
  links: p.file.outlinks.length,
  backlinks: p.file.inlinks.length,
  total: p.file.outlinks.length + p.file.inlinks.length
})).sort((a, b) => b.total - a.total).slice(0, 15);

dv.header(3, "🔗 链接最密集的笔记 Top 15");
dv.table(
  ["笔记", "出链", "入链", "总计"],
  stats.map(s => [s.name, s.links, s.backlinks, s.total])
);

// 孤岛笔记(无链接)
const orphans = pages.where(p => p.file.outlinks.length === 0 && p.file.inlinks.length === 0);
dv.header(3, `🏝️ 孤岛笔记 (${orphans.length})`);
if (orphans.length > 0) {
  dv.list(orphans.limit(10).file.link);
}

配方 9:批量属性补全

使用 Templater 批量为笔记添加缺失的属性:

javascript
<%*
// 批量为 books/ 下的笔记添加缺失属性
const files = app.vault.getMarkdownFiles()
  .filter(f => f.path.startsWith("books/"));

let count = 0;
for (let file of files) {
  const content = await app.vault.read(file);
  const hasStatus = content.includes("status:");
  const hasRating = content.includes("rating:");
  
  if (!hasStatus || !hasRating) {
    const newContent = content.replace(/^---\n/, `---\n${!hasStatus ? "status: to-read\n" : ""}${!hasRating ? "rating: \n" : ""}`);
    await app.vault.modify(file, newContent);
    count++;
  }
}
tR += `已更新 ${count} 个文件`;
-%>

配方 10:自动生成目录页

dataviewjs
// 自动为指定文件夹生成目录页
const folder = dv.current().file.folder;
const pages = dv.pages(`"${folder}"`)
  .where(p => p.file.name !== dv.current().file.name)
  .sort(p => p.file.name);

dv.header(2, `📂 ${folder} 目录 (${pages.length} 篇)`);

// 按标签分组
const byTag = {};
for (let p of pages) {
  const tag = p.tags ? p.tags[0] : "未分类";
  if (!byTag[tag]) byTag[tag] = [];
  byTag[tag].push(p);
}

for (let [tag, group] of Object.entries(byTag).sort()) {
  dv.header(3, `${tag} (${group.length})`);
  dv.list(group.map(p => p.file.link));
}

配方 11:读书进度追踪

dataviewjs
// 自动计算阅读进度并提醒
const books = dv.pages('"books"').where(p => p.status === "reading");

if (books.length === 0) {
  dv.paragraph("📖 当前没有正在阅读的书籍");
} else {
  dv.header(3, "📖 阅读进度追踪");
  
  for (let book of books) {
    const progress = book.total_pages && book.total_pages > 0 
      ? Math.round((book.current_page || 0) / book.total_pages * 100) 
      : 0;
    const filled = Math.floor(progress / 5);
    const bar = "█".repeat(filled) + "░".repeat(20 - filled);
    
    dv.paragraph(
      `${book.file.link}\n\`${bar}\` ${progress}% (${book.current_page || 0}/${book.total_pages || "?"})`
    );
  }
}

配方 12:知识盲区检测

dataviewjs
// 检测哪些标签下的笔记数量太少(可能存在知识盲区)
const tagCounts = {};
const pages = dv.pages().where(p => p.tags);

for (let p of pages) {
  for (let tag of p.tags) {
    tagCounts[tag] = (tagCounts[tag] || 0) + 1;
  }
}

const sorted = Object.entries(tagCounts).sort((a, b) => a[1] - b[1]);
const sparse = sorted.filter(([tag, count]) => count <= 2);

dv.header(3, `🔍 知识盲区检测 (${sparse.length} 个标签仅 1-2 篇笔记)`);
if (sparse.length > 0) {
  dv.table(
    ["标签", "笔记数", "建议"],
    sparse.slice(0, 15).map(([tag, count]) => [
      tag, 
      count, 
      count === 1 ? "考虑补充更多笔记或合并到相关标签" : "考虑补充更多内容"
    ])
  );
}

三件套联动最佳实践

工作流设计原则

  1. 单一职责:每个模板只做一件事
  2. 模板命名规范模板名-用途.md
  3. 属性先行:所有模板都应包含标准化 frontmatter
  4. 渐进式自动化:先手动 → 再模板化 → 最后自动化
  5. 定期审查:每月检查模板是否需要更新

推荐插件配置顺序

1. 安装 Templater → 设置模板目录
2. 安装 QuickAdd → 配置快速捕获
3. 安装 Dataview → 启用 JavaScript 查询
4. 创建基础模板 → 测试工作流
5. 逐步添加自动化配方

相关文档