前言
以前一直在用微软的 OneNote
作为笔记软件,进行资料收集和文件整理,后来在经理了一次 OneDrive
误删文件倒是 OneNote
整个笔记本丢失以后,就对这些云端方案不是很感兴趣了。于是在搜寻本地化的解决方案,网上推荐最多是 notion
和 obsidian
,调研了一番以后,选择了全面开源并免费的 obsidian
作为知识管理工具,同时也作为日常随笔记录的工具。并且基于 markdown
的写作,也方便快速通过 hexo
将内容转换为博文进行发布。
一、安装与插件
1.1 安装
Obsidian
的安装非常简单,参考 电脑重装纪实,直接一条 winget install Obsidian.Obsidian
命令即可安装。
1.2 需求分析与插件选择
Obsidian
支持第三方插件,并且在软件中内置了社区插件检索,在选项-第三方插件
中,关闭安全模式
即可使用 Obsidian
庞大的第三方插件库。
本人在日常记录方面有如下几个需求:
- 支持快速检索:格式统一,分类自由,创建便利,方便检索。
- 支持账单统计:方便高效的记录每一笔收支,方便控制消费欲望,避免盲目消费。
- 多端记录同步:台式机、笔记本、手机、平板等设备可以互相同步。
Obsidian
本身自带的日记、ZK 卡片功能就可以快速构建笔记,而其他功能大部分都可以找到满足需求的社区插件,总结列表如下:
- (官方)日记插件:满足日记的快速生成,同时利用模板可以统计格式。
- (官方)ZK 卡片插件:快速生成临时笔记,记录偶然的想法。
- (社区)Templater 插件:模板增强插件,提供了强大的语法支持,更方便在文档创建时规整格式。
- (社区)Calendar 插件:增强日历功能,在侧面板中提供日历视图,快速定位日记,同时支持周记的生成,进一步归纳总结思路。
- (社区)Checklist 插件:在侧面板中提供任务清单视图,可以快速检索未完成的任务。
- (社区)Dataview 插件:提供强大的数据查询功能,利用其提供的语法,可以快速整理计算每日账单总额。
- (社区)Remotely Save 插件:提供远程存储和同步。
1.3 插件配置
-
Templater 插件:
-
首先构建一个用于存放模板的目录,由于目录管理默认安装字符排序,所以推荐直接在目录前加上数字,我这里选择
0-模板
作为模板目录。 -
将插件的
Syntax Highlighting
、Automatic jump to cursor
、Trigger Templater on new file creation
三个功能全部激活。 -
记账、日记、周记、ZK 卡片总共四个模板,具体代码如下,可以根据需求进行加减。
- 记账模板(转账通过一笔支出一笔收入实现)
-
js123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293<%* //判断模板应用模式 if(tp.config.run_mode==0){ //如果通过新建笔记应用模板,则将笔记存放到指定位置 tp.file.move("/2-日记/2.1-账单/"+tp.date.now("YYYYMMDDHHmmss")) } //账单类型(清账用于管理账户余额) const bill_type=[ "支出", "收入", "清账" ] //消费账户(根据需求设置消费所使用的账户) const bill_account=[ "微信", "支付宝", "其他" ] //消费渠道(根据需求设置消费渠道) const bill_source = [ "线下支付", "在线支付", "淘宝", "京东" ] //消费类型(根据需求设置消费类型) const expense_type=[ "食品酒水", "日常用品", "学习进修", "衣服饰品", "数码产品", "行车交通", "交流通讯", "寝室住宿", "休闲娱乐", "人情往来", "医疗保险", "转账", "其他" ] //收入类型(根据需求设置收入类型) const income_type=[ "工资", "转账", "生活费", "红包" ] //首先选择账单类型 billType= await tp.system.suggester(bill_type, bill_type,false,'请选择账单类型') //随后根据不同类型选择不同记录过程 //支出 if (billType == bill_type[0]) { billAccount = await tp.system.suggester(bill_account, bill_account,false,'请选择消费账户') billSource = await tp.system.suggester(bill_source, bill_source,false,'请选择消费渠道') type = await tp.system.suggester(expense_type,expense_type,false,'请选择账单类型') goods = await tp.system.prompt("请输入账单内容") price = await tp.system.prompt("请输入价格") date = await tp.system.prompt("请输入账单日期",tp.date.now("YYYY-MM-DD")) } //收入 if (billType == bill_type[1]) { billAccount = await tp.system.suggester(bill_account, bill_account,false,'请选择入账账户') billSource = await tp.system.suggester(bill_source, bill_source,false,'请选择入账资金来源') type = await tp.system.suggester(income_type,income_type,false,'请选择收入类型') goods = await tp.system.prompt("请输入入账明细") price = await tp.system.prompt("请输入入账金额") date = await tp.system.prompt("请输入入账日期",tp.date.now("YYYY-MM-DD")) } //清账 if (billType == bill_type[2]) { billAccount = await tp.system.suggester(bill_account, bill_account,false,'请选择清账账户') billSource = "手动输入" type = "资金清账" goods = "清账" price = await tp.system.prompt("请输入目前账户金额") date = await tp.system.prompt("请输入清账日期",tp.date.now("YYYY-MM-DD")) } -%> --- tags: - 账单 date: <% date %> goods: - <% goods %><% tp.file.cursor(0) %> type: <% type %> price: <% price %> billSource: <% billSource %> billAccount: <% billAccount %> billType: <% billType %> --- [[<% tp.date.now("YYYY-MM-DD ddd", 0, date, "YYYY-MM-DD") %>]]
code12. 日记模板(在生成模板的同时,链接到前一天后一天以及当周周报)
js1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889--- title: tiger 的生活小记 (<% tp.date.now("YYYY-MM-DD", 0, tp.file.title, "YYYY-MM-DD ddd") %>) author: tiger categories: - 生活 location: - 地点 locations: weather: - 天气 tags: - 日记 date: <% tp.date.now("YYYY-MM-DD ddd") %> --- <<[[<% tp.date.now("gggg-[W]ww", 0, tp.file.title, "YYYY-MM-DD ddd") %>|每周总结]]>> << [[<% tp.date.now("YYYY-MM-DD ddd", -1, tp.file.title, "YYYY-MM-DD ddd") %>]] | [[<% tp.date.now("YYYY-MM-DD ddd", 1, tp.file.title, "YYYY-MM-DD ddd") %>]] >> ## 生活记录 ### 上午`(06:00-13:00)` ### 下午`(13:00-18:00)` ### 晚上`(18:00-24:00)` ### 熬夜`(24:00-06:00)` ## 学习记录 ## 待办事项 #todo - [ ] ## ZK 卡片 ```dataviewjs const data = dv.pages('"7-ZK 卡片"') //查询 ZK 卡片目录下的笔记 .where( b => dv.equal(b.date.split(" ")[0],"<% tp.date.now("YYYY-MM-DD", 0, tp.file.title, "YYYY-MM-DD ddd") %>"))//过滤出当天卡片 const tableData = data.sort(b => b.date,'desc') //按日期倒序 .map(b => [b.file.link, b.title,b.date]) //取出主要字段 dv.table(["笔记", "标题","创建时间"], tableData) //收入表格 ``` ## 日常收支 ```dataviewjs const data = dv.pages('"2-日记/2.1-账单"') //查询账单目录下的笔记 .where(b=> dv.equal(b.date,dv.date("<% tp.date.now("YYYY-MM-DD", 0, tp.file.title, "YYYY-MM-DD ddd") %>")))//过滤出当天账单 const indata = data.where(b => dv.equal(b.billType,"收入")) const outdata = data.where(b => dv.equal(b.billType,"支出")) const intableData = indata.sort(b => b.date,'desc') //按日期倒序 .map(b => [b.file.link, b.billSource,b.billAccount, b.type, b.date, b.goods, b.price]) //取出主要字段 const outtableData = outdata.sort(b => b.date,'desc') //按日期倒序 .map(b => [b.file.link, b.billSource,b.billAccount, b.type, b.date, b.goods, b.price]) //取出主要字段 var totalout = 0 var totalin =0 // 统计收入总计 for(let price of indata.price.array()) { totalin += price } // 统计消费总计 for(let price of outdata.price.array()) { totalout += price } dv.header(3, "汇总") const a='账单数量:'+ data.length //账单数量 const b='消费汇总:¥'+ Math.round(totalout*100-totalin*100)/100 //收支总计 var num= data.length var sum=Math.round(totalin*100-totalout*100)/100 dv.table(["账单数量", "结余汇总¥"], dv.array([[[num],[sum]]])) //收入表格 if(totalout>0){ dv.header(4, "支出明细") const c='支出总计:¥'+ Math.round(totalout*100)/100 //消费总计 dv.list([c]) dv.table(["笔记", "来源","账户", "类型","日期", "商品", "价格¥"], outtableData) //支出表格 } if(totalin>0){ dv.header(4, "收入明细") const d='收入总计:¥'+ Math.round(totalin*100)/100 //收入总计 dv.list([d]) dv.table(["笔记", "来源","账户", "类型","日期", "商品", "价格¥"], intableData) //收入表格 } ```
code13. 周记模板(汇总当周收支,并连接每天的日记)
js1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768--- title: tiger 的生活小记 (<% tp.date.now("YYYY-MM-DD", 0, tp.file.title, "gggg-[W]ww") %> - <% tp.date.now("YYYY-MM-DD", 6, tp.file.title, "gggg-[W]ww") %>) author: tiger categories: - 生活 tags: - 周记 --- << [[<% tp.date.now("YYYY-MM-DD ddd", 0, tp.file.title, "gggg-[W]ww") %>]] | [[<% tp.date.now("YYYY-MM-DD ddd", 1, tp.file.title, "gggg-[W]ww") %>]] | [[<% tp.date.now("YYYY-MM-DD ddd", 2, tp.file.title, "gggg-[W]ww") %>]] | [[<% tp.date.now("YYYY-MM-DD ddd", 3, tp.file.title, "gggg-[W]ww") %>]] | [[<% tp.date.now("YYYY-MM-DD ddd", 4, tp.file.title, "gggg-[W]ww") %>]] | [[<% tp.date.now("YYYY-MM-DD ddd", 5, tp.file.title, "gggg-[W]ww") %>]] | [[<% tp.date.now("YYYY-MM-DD ddd", 6, tp.file.title, "gggg-[W]ww") %>]]>> ## 每周总结 ```dataviewjs const data = dv.pages('"7-ZK 卡片"') //查询 ZK 卡片目录下的笔记 .where(b=> dv.date(b.date.split(" ")[0]) >= dv.date("<% tp.date.now("YYYY-MM-DD", 0, tp.file.title, "gggg-[W]ww") %>"))//过滤出当周卡片 .where(b=> dv.date(b.date.split(" ")[0]) <= dv.date("<% tp.date.now("YYYY-MM-DD", 6, tp.file.title, "gggg-[W]ww") %>"))//过滤出当周卡片 dv.header(3, "卡片汇总") const tableData = data.sort(b => b.date,'desc') //按日期倒序 .map(b => [b.file.link, b.title,b.date]) //取出主要字段 dv.table(["笔记", "标题","创建时间"], tableData) //收入表格 ``` ```dataviewjs const data = dv.pages('"2-日记/2.1-账单"') //查询账单目录下的笔记 .where(b=> b.date >= dv.date("<% tp.date.now("YYYY-MM-DD", 0, tp.file.title, "gggg-[W]ww") %>"))//过滤出当周账单 .where(b=> b.date <= dv.date("<% tp.date.now("YYYY-MM-DD", 6, tp.file.title, "gggg-[W]ww") %>"))//过滤出当周账单 const indata = data.where(b => dv.equal(b.billType,"收入")) const outdata = data.where(b => dv.equal(b.billType,"支出")) const intableData = indata.sort(b => b.date,'desc') //按日期倒序 .map(b => [b.file.link, b.billSource,b.billAccount, b.type, b.date, b.goods, b.price]) //取出主要字段 const outtableData = outdata.sort(b => b.date,'desc') //按日期倒序 .map(b => [b.file.link, b.billSource,b.billAccount, b.type, b.date, b.goods, b.price]) //取出主要字段 var totalout = 0 var totalin =0 // 统计收入总计 for(let price of indata.price.array()) { totalin += price } // 统计消费总计 for(let price of outdata.price.array()) { totalout += price } dv.header(3, "汇总") const a='账单数量:'+ data.length //账单数量 const b='消费汇总:¥'+ Math.round(totalout*100-totalin*100)/100 //收支总计 var num= data.length var sum=Math.round(totalin*100-totalout*100)/100 dv.table(["账单数量", "结余汇总¥"], dv.array([[[num],[sum]]])) //收入表格 if(totalout>0){ dv.header(4, "支出明细") const c='支出总计:¥'+ Math.round(totalout*100)/100 //消费总计 dv.list([c]) dv.table(["笔记", "来源","账户", "类型","日期", "商品", "价格¥"], outtableData) //支出表格 } if(totalin>0){ dv.header(4, "收入明细") const d='收入总计:¥'+ Math.round(totalin*100)/100 //收入总计 dv.list([d]) dv.table(["笔记", "来源","账户", "类型","日期", "商品", "价格¥"], intableData) //收入表格 } ```
code14. ZK 模板
js1234567891011121314--- title: <% title = await tp.system.prompt("请输入卡片标题") %> aliases: [<% title %>] author: tiger tags: - date: '<% tp.date.now("YYYY-MM-DD HH:MM:SS",0,tp.file.title,"YYYYMMDDHHMMSS") %>' <%tp.file.rename(tp.date.now("YYYYMMDD-",0,tp.file.title,"YYYYMMDDHHMMSS") +title)%> --- << [[<% tp.date.now("YYYY-MM-DD ddd") %>]] >> ## <% title %> ## 参考 -
- 日记插件:
- 将日期格式改为
YYYY-MM-DD ddd
。前一节的日记模板通过读取文件名称获取日期,需要时间格式在语法上一直,本文将时间格式设置为2022-06-05 周日
。 - 设置新日记保存目录,本文将其设置为
2-日记
,前一节账单目录为/2-日记/2.1-账单/
。 - 根据模板名称,设置日记模板位置,本文为
0-模板/日记模板
。
- 将日期格式改为
- ZK 卡片插件:
- 设置新卡片保存目录,本文将其设置为
7-ZK卡片
。 - 根据模板名称,设置 ZK 卡片模板位置,本文为
0-模板/ZK模板
。 - 设置 ZK 卡 ID 格式,本文将其设置为
YYYYMMDDHHMMSS
。参考样例20220605160629
,精确到秒防止连续创建导致卡片重名。
- 设置新卡片保存目录,本文将其设置为
- Calendar 插件:
- 设置每周开始时间,默认为周一。
- 打开
Show week number
,方便建立周报。 - 在
Weekly Note Settings
中:- 将
Weekly note format
设置为gggg-[W]ww
。参考样例为2022-W23
。 - 将
Weekly note template
设置为0-模板/周记模板
。 - 将
Weekly note folder
设置为2-日记
。
- 将
- Checklist 插件:
- 根据需求,在
Tag name
中添加检索用的tag
,默认只有todo
,可以再添加一个中文的待办事项
。
- 根据需求,在
- Dataview 插件:
- 打开
Enable JavaScript Queries
。 - 将
Date Format
设置为yyyy-MM-dd
,参考样例为2022-06-05
。 - 将
Date + Time Format
设置为yyyy-MM-dd t
,参考样例为2022-06-05 16:47
。
- 打开
- Remotely Save 插件:(本文使用
webdav
作为远程存储方式,以下以坚果云为例)- 注册 坚果云 账户,登录后,在安全选项页面中,添加应用,获取对应密码。坚果云默认的 WebDAV 地址为 https://dav.jianguoyun.com/dav/。
- 在插件的
WebDav
设置中,对应填写服务器地址
,用户名
,密码
,随后检查连接是否可用。 - 在插件的基本设置中,修改运行条件,本文设置为
启动后30s运行一次
,每30分钟
运行一次。
二、运行
2.1 日记功能
在 Obsidian
主页面右侧找到日记插件界面,点击每日日期或左侧周数,即可创建对应笔记。
2.2 todo 列表
在 Obsidian
主页面右侧找到 Tode list 插件界面,快速确定每个任务完成情况。
2.3 可视化
在 Obsidian
的关系图谱页面中,可以清晰的看到每笔日记的关联关系。
三、总结
目前 Obsidian
完美的满足了我对应全部文档数据的掌控欲,终究还是将数据存在本地比较安心。后续 Obsidian
还有许多有意思的功能值得分享,比如文本导出 PDF
、Word
,地理地图,整合 zotero
等。