相信大多数热爱阅读的人也会喜欢将读过的书以及读书的记录保存下来,我也不例外。最开始我尝试过使用最原始的文本的方式进行记录,后来又使用了阅读记录这款app。
一年多的使用下来,我感觉阅读记录app确实是一个挺不错的应用,但是不适合我。作为一个免费用户,阅读记录app只允许同时最多记录两本书的阅读进度,这对我来说是件好事,可以专注于一两本书上读完再去读下一本。
而对于我这个想将个人数据都掌握在自己手上的人来说,想要从阅读记录app中导出阅读记录数据只有开通价值168元的永久会员这一个选项,阅读记录app主推的另一个OCR书摘功能我却完全用不上。所以我不愿意为了导出数据这一个功能去花费那么高昂的会员费,并且我认为这是一款数据记录软件本就该无条件提供的功能。
其实想来仅仅记录阅读数据并不是一个很复杂的功能,我为什么不能在个人数据中心项目基础上,开发了一套属于我自己的阅读记录系统呢。下图是我最终实现的效果:
业务流程图
参考阅读记录app的使用流程,我为自己的阅读记录系统设计了如下的业务流程:
- 当开始一本书时,会首先检查它是否在于书单里面,只有存在才可以开始阅读;
- 在同一时刻只允许阅读一本书,除非你取消本次阅读或者结束(完成)本次阅读;
- 当阅读结束的那一刻,记录下此次阅读的时长和进度,然后更新相关数据表。
数据表设计
基于上述业务流程,我设计了两张数据表用于数据存储。
dim_notiondb_book_list_info
该表是一张维度表,用于存储书单信息,包括书记的书名作者等基本信息。该表存储在Notion上,然后通过数据采集系统将其同步定时到MySQL数据库,我们仅需在Notion上进行书籍的数据录入即可。数据采集代码在之前的文章已经介绍,在次不再赘述。
表结构
字段名 | Notion数据类型 | MySQL数据类型 | 备注 |
---|---|---|---|
id | 文本 | String | 页面id |
book_name | 标题 | String | 书名 |
auther_name | 文本 | String | 作者名 |
auther_country | 文本 | String | 作者国籍 |
book_type | 多选 | String | 图书类型 |
book_price | 数字 | Float | 图书价格 |
book_patform | 多选 | String | 阅读平台 |
read_datetime_start | 日期 | DateTime | 阅读开始时间 |
read_datetime_end | 日期 | DateTime | 阅读结束时间 |
book_page_readed | 数字 | Float | 已读页数 |
book_page_all | 数字 | Float | 总页数 |
status | 单选 | String | 阅读状态 |
dwd_book_read_record
阅读记录表数据事实表,直接在MySQL中创建,用于存储阅读事实记录。
阅读记录数据根据status
字段值的不同可以分为reading
、cancel
、end
三种数据,其中reading
最为特殊,整张表里面只允许最多存在一条状态为reading
的数据,它约束了同一时刻只能阅读一本书。
表结构
字段名 | 数据类型 | 备注 |
---|---|---|
id | int | 自增id |
book_name | varchar | 书名(与书单书名对齐) |
page_start | float | 阅读开始的页码(使用浮点数兼容百分比进度,不小于0) |
page_end | float | 阅读结束的页码(使用浮点数兼容百分比进度,不大于图书总页码) |
datetime_start | datetime | 阅读开始的时间 |
datetime_end | datetime | 阅读结束的时间(取消或结束的时间) |
read_time | int | 阅读时长(单位分钟,不小于0,不大于开始、结束时间之差,可人为指定) |
status | varchar | 阅读状态(reading、cancel、end,全表只能有一条reading记录) |
is_finish | int | 是否读完(1:读完,0:未读完。当结束页码等于图书总页码时为1) |
交互指令
根据上面的业务流程,我具体设计了四条操作指令。
阅读记录
- 格式:
阅读记录
- 参数:无
- 返回值:
- 返回当前正在阅读的记录信息(status=’reading’),包括书名,开始时间,已阅读的时间;
- 没有正在阅读的记录则返回“当前无正在阅读的记录”
阅读开始
- 格式:
阅读开始 [书名] 开始:[开始页码]
- 参数:
- 书名:必选,必须在书单中存在
- 开始页码:可选,必须为数字
- 返回值:
- 提示“开始阅读 [书名] [开始时间]”,并根据其历史阅读数据分析其仍需阅读的天数和小时数等信息;
- 没有历史阅读数据或没有最大页码则进行相应提示;
- 如果书单没有这本书,则提示“ [书名] 未录入书单”;
- 如果存在正在阅读的记录,则提示“请先结束阅读 [书名] [开始时间]”
阅读结束
- 格式:
阅读结束 开始:[开始页码] 结束:[结束页码] 已读完 时长:[阅读时长]
- 参数:
- 开始页码:可选,默认为上一次阅读的结束页码或0(没有历史记录或上一次历史记录为已读完)
- 结束页码:可选,数字,大于等于总页码则默认为已读完
- 已读完:与结束页码至少有一个存在,若选择已读完,则无论结束页码为多少都标记本书已读完
- 阅读时长:可选,默认为开始和结束时间的时间差,单位为分
- 返回值:
- 如果存在正在阅读的记录,则设置为取消(status=’cancel’),并提示“已结束阅读 [书名] [开始时间]~[结束时间] [阅读时长] [阅读进度]”,以及根据其历史阅读数据分析其仍需阅读的天数和小时数等信息;;
- 如果本书读完,则提示“已读完本书!”
- 如果不存在正在阅读的记录,则提示“当前没有正在阅读的记录”
阅读取消
- 格式:
阅读取消
- 参数:无
- 返回值:
- 如果存在正在阅读的记录,则设置为取消(status=’cancel’),并提示“已取消阅读 [书名] [开始时间]”;
- 如果不存在正在阅读的记录,则提示“当前无正在阅读的记录”
代码实现
由于代码过长,就不直接贴出来了,下方提供了源码的下载链接,需要的朋友请直接下载。具体的模块注册请参照后端框架中的实现说明。
依赖文件:
阅读记录模块:
数据采集脚本:
相关代码已托管于GitHub,欢迎Star!