refactor(api): 去除代码版本命名
No files matched your search
@@ -1,7 +1,7 @@
|
||||
# v2 数据接口(/api/v2/*)
|
||||
# 当前数据接口(/api/reading/*)
|
||||
|
||||
「阅间」新版前端的数据来源。实现在 `api_v2.py`(Flask Blueprint,注册于 `app.py`),
|
||||
v1 的 `/api/*` 接口保持不变,两套接口可同时使用。
|
||||
「阅间」当前前端的数据来源。实现在 `reading_api.py`(Flask Blueprint,注册于 `app.py`),
|
||||
旧版 `/api/*` 接口保持不变;`/api/v2/*` 仅作为兼容路径保留。
|
||||
|
||||
## 数据来源与优先级
|
||||
|
||||
@@ -21,20 +21,20 @@ MySQL 不可用时,阅读数据接口仍可降级运行(返回 `degraded: tr
|
||||
|
||||
| 方法 | 路径 | 参数 | 说明 |
|
||||
|------|------|------|------|
|
||||
| GET | `/api/v2/status` | — | 连接状态、书架规模、数据快照时间 |
|
||||
| GET | `/api/v2/shelf` | `tab=all\|reading\|done\|wish`、`keyword`、`limit`、`offset`、`progress=1` | 书架列表 + 书单 + 有声书 + 文章收藏入口(`progress=1` 为首屏书籍实时补拉进度) |
|
||||
| GET | `/api/v2/dashboard` | `period=week\|month\|year\|overall` | 整页概览:趋势柱状图、四张统计卡、读得最多、偏好方向、时段分布、阅读画像、年度小结 |
|
||||
| GET | `/api/v2/notebooks` | — | 笔记本概览(有笔记的书 + 划线/想法/书签数量) |
|
||||
| GET | `/api/v2/notes` | `book_id`(`all` 表示聚合笔记最多的前 N 本)、`limit` | 划线与想法正文,按时间倒序 |
|
||||
| GET | `/api/v2/book/<book_id>` | — | 书籍详情聚合:简介 + 进度 + 目录 + 我的笔记 + 热门划线 + 点评 + 相似推荐 |
|
||||
| GET | `/api/v2/book/<book_id>/reviews` | `type=0\|1\|2\|3\|4`(全部/推荐/不行/最新/一般)、`count` | 公开点评(按类型筛选) |
|
||||
| GET | `/api/v2/book/<book_id>/highlights` | `chapter_uid`(0=全书) | 热门划线(人数、章节、位置、跳转链接) |
|
||||
| GET | `/api/v2/book/<book_id>/underline-thoughts` | `chapter_uid`、`range` | 某条划线下的他人想法 |
|
||||
| GET | `/api/v2/thought/<review_id>` | — | 单条想法详情:正文、划线原文、点赞、评论 |
|
||||
| GET | `/api/v2/archives` | — | 书架书单及成员书籍 |
|
||||
| GET | `/api/v2/recommend` | `maxIdx` | 个性化推荐 |
|
||||
| GET | `/api/v2/search` | `keyword`、`scope=all\|books\|author\|lists\|audio\|fulltext\|novel\|account\|article` | 书城检索(按分组归一为书籍/作者/书单) |
|
||||
| POST | `/api/sync` | — | v1 已有:重新采集数据并迁移到 MySQL |
|
||||
| GET | `/api/reading/status` | — | 连接状态、书架规模、数据快照时间 |
|
||||
| GET | `/api/reading/shelf` | `tab=all\|reading\|done\|wish`、`keyword`、`limit`、`offset`、`progress=1` | 书架列表 + 书单 + 有声书 + 文章收藏入口(`progress=1` 为首屏书籍实时补拉进度) |
|
||||
| GET | `/api/reading/dashboard` | `period=week\|month\|year\|overall` | 整页概览:趋势柱状图、四张统计卡、读得最多、偏好方向、时段分布、阅读画像、年度小结 |
|
||||
| GET | `/api/reading/notebooks` | — | 笔记本概览(有笔记的书 + 划线/想法/书签数量) |
|
||||
| GET | `/api/reading/notes` | `book_id`(`all` 表示聚合笔记最多的前 N 本)、`limit` | 划线与想法正文,按时间倒序 |
|
||||
| GET | `/api/reading/book/<book_id>` | — | 书籍详情聚合:简介 + 进度 + 目录 + 我的笔记 + 热门划线 + 点评 + 相似推荐 |
|
||||
| GET | `/api/reading/book/<book_id>/reviews` | `type=0\|1\|2\|3\|4`(全部/推荐/不行/最新/一般)、`count` | 公开点评(按类型筛选) |
|
||||
| GET | `/api/reading/book/<book_id>/highlights` | `chapter_uid`(0=全书) | 热门划线(人数、章节、位置、跳转链接) |
|
||||
| GET | `/api/reading/book/<book_id>/underline-thoughts` | `chapter_uid`、`range` | 某条划线下的他人想法 |
|
||||
| GET | `/api/reading/thought/<review_id>` | — | 单条想法详情:正文、划线原文、点赞、评论 |
|
||||
| GET | `/api/reading/archives` | — | 书架书单及成员书籍 |
|
||||
| GET | `/api/reading/recommend` | `maxIdx` | 个性化推荐 |
|
||||
| GET | `/api/reading/search` | `keyword`、`scope=all\|books\|author\|lists\|audio\|fulltext\|novel\|account\|article` | 书城检索(按分组归一为书籍/作者/书单) |
|
||||
| POST | `/api/sync` | — | 旧版已有:重新采集数据并迁移到 MySQL |
|
||||
|
||||
## 与微信读书接口的字段口径
|
||||
|
||||
@@ -42,11 +42,11 @@ MySQL 不可用时,阅读数据接口仍可降级运行(返回 `degraded: tr
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/api/v2/goals` | 返回 `{"goals":[...]}`,成员按书籍 ID 排序 |
|
||||
| POST | `/api/v2/goals` | 新建,成功返回 201 和 `{"goal":{...}}` |
|
||||
| PUT | `/api/v2/goals/<id>` | 整体替换目标和书目,返回 `{"goal":{...}}` |
|
||||
| DELETE | `/api/v2/goals/<id>` | 删除目标及其成员,返回 `{"ok":true}` |
|
||||
| POST | `/api/v2/goals/import` | 请求 `{"goals":[...]}`,返回 `{"imported":新增数量}` |
|
||||
| GET | `/api/reading/goals` | 返回 `{"goals":[...]}`,成员按书籍 ID 排序 |
|
||||
| POST | `/api/reading/goals` | 新建,成功返回 201 和 `{"goal":{...}}` |
|
||||
| PUT | `/api/reading/goals/<id>` | 整体替换目标和书目,返回 `{"goal":{...}}` |
|
||||
| DELETE | `/api/reading/goals/<id>` | 删除目标及其成员,返回 `{"ok":true}` |
|
||||
| POST | `/api/reading/goals/import` | 请求 `{"goals":[...]}`,返回 `{"imported":新增数量}` |
|
||||
|
||||
新建、编辑和导入中的目标字段一致:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 微信读书数据展示网站 - 元数据文档
|
||||
|
||||
> 版本:2.0.0 | 更新时间:2026-07-17 | 数据库:MySQL weread_dashboard | 数据模型版本:v2.0
|
||||
> 更新时间:2026-07-17 | 数据库:MySQL weread_dashboard | 数据模型:完整阅读数据表
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 微信读书数据展示网站 - 技术文档
|
||||
|
||||
> 版本:2.0.0 | 更新时间:2026-07-17 | 作者:WorkBuddy | 数据模型版本:v2.0(31 表)
|
||||
> 更新时间:2026-07-17 | 作者:WorkBuddy | 数据模型:完整阅读数据表
|
||||
|
||||
---
|
||||
|
||||
@@ -278,9 +278,9 @@ HTTP 503 Service Unavailable
|
||||
- 连接失败时显示固定告警横幅,阻止后续数据加载
|
||||
- 使用 `db_required` 装饰器统一处理数据库连接异常
|
||||
|
||||
### 4.4 数据模型 v2.0 设计规范
|
||||
### 4.4 数据模型设计规范
|
||||
|
||||
基于微信读书官方 8 份 API 文档的完整字段分析,数据模型 v2.0 遵循以下设计规范:
|
||||
基于微信读书官方 8 份 API 文档的完整字段分析,数据模型遵循以下设计规范:
|
||||
|
||||
**双列时间戳模式**:所有整型 Unix 时间戳字段(`INT UNSIGNED`)均伴随一个 `_dt TIMESTAMP` 列,例如 `update_time` ↔ `update_time_dt`。便于直接查询展示,同时保留原始时间戳用于排序和计算。
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
完整功能、业务规则、接口落点与状态见 [功能目标清单](feature-checklist.md)。该清单先于本轮实现建立,后续代码开发继续追加和更新。
|
||||
|
||||
此版本属于 2.0 设计探索。正式版本需要接入真实接口、完成验收并合并到正式 Web 项目的 `master`,随后再创建 `v2.0` 标签。
|
||||
该设计探索已归档,当前正式看板由根目录 Flask 服务提供。
|
||||
|
||||
## 数据流
|
||||
|
||||
@@ -67,7 +67,7 @@ GitHub Actions 的 `.github/workflows/deploy.yml` 监听 `dev` 分支。分支 p
|
||||
|
||||
## 正式看板的阅读目标持久化
|
||||
|
||||
正式看板使用 `static/js/app.js`、`static/js/weapi.js` 和 `api_v2.py`。本节覆盖正式页面;前文的 Demo 存储方式不适用于正式目标。
|
||||
正式看板使用 `static/js/app.js`、`static/js/weapi.js` 和 `reading_api.py`。本节覆盖正式页面;前文的 Demo 存储方式不适用于正式目标。
|
||||
|
||||
`reading_goals` 保存 `id`、`name`、`start_date`、`end_date`、来源书单名称 `sources` 和创建、修改时间。`reading_goal_books` 保存 `goal_id`、`book_id`,联合主键防止同一目标重复计书。目标 ID 沿用前端生成值,便于导入旧目标。来源名称保存为 JSON 数组,不表示持续关联书单。
|
||||
|
||||
@@ -81,4 +81,4 @@ GitHub Actions 的 `.github/workflows/deploy.yml` 监听 `dev` 分支。分支 p
|
||||
|
||||
完成率和状态不写入目标表。当前已知已读状态用于计算,不要求在目标日期内读完;全部已读完优先显示“已完成”,否则按浏览器本地日期显示未开始、进行中或已到期,起止当天均属于进行中。未知状态不计为已完成,但仍计入分母。
|
||||
|
||||
旧数据仅在用户点击导入时发送给 `/api/v2/goals/import`。先校验整批,再在事务中逐项插入;相同 ID 已存在时保留数据库内容,批次内重复 ID 只处理第一条。例如库中已有 G1,导入 `[G1, G2, G2]` 返回 `{"imported":1}`,再次导入返回 `{"imported":0}`。任何写入失败均回滚整批;成功后保留原浏览器备份并记录导入标记。
|
||||
旧数据仅在用户点击导入时发送给 `/api/reading/goals/import`。先校验整批,再在事务中逐项插入;相同 ID 已存在时保留数据库内容,批次内重复 ID 只处理第一条。例如库中已有 G1,导入 `[G1, G2, G2]` 返回 `{"imported":1}`,再次导入返回 `{"imported":0}`。任何写入失败均回滚整批;成功后保留原浏览器备份并记录导入标记。
|
||||
@@ -32,11 +32,11 @@ git checkout dev
|
||||
git pull --ff-only origin dev
|
||||
python3 -m venv .venv # 仅 .venv 不存在时执行
|
||||
.venv/bin/python -m pip install -r requirements.txt
|
||||
# 读取 api_v2.MYSQL_CONFIG 后执行 migrations/001_reading_goals.sql
|
||||
# 读取 reading_api.MYSQL_CONFIG 后执行 migrations/001_reading_goals.sql
|
||||
sudo systemctl restart "$SERVICE_NAME"
|
||||
```
|
||||
|
||||
其中迁移实际通过 `api_v2.MYSQL_CONFIG` 读取数据库配置并执行 SQL 文件;SQL 使用 `CREATE TABLE IF NOT EXISTS`,可重复执行。
|
||||
其中迁移实际通过 `reading_api.MYSQL_CONFIG` 读取数据库配置并执行 SQL 文件;SQL 使用 `CREATE TABLE IF NOT EXISTS`,可重复执行。
|
||||
|
||||
## systemd 示例
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> 创建日期:2026-09-11。本文先于本轮 Demo 开发建立,是后续实现、验收和追加需求的统一清单。
|
||||
|
||||
当前版本定位:本目录中的静态 Demo 是 2.0 设计探索,不是正式 2.0 发布。只有后续真实功能合并到正式 Web 项目的 `master` 并完成验收后,才创建 `v2.0` 标签。
|
||||
当前正式看板已接入真实接口;静态 Demo 仅作为历史设计稿保留。
|
||||
|
||||
## 使用方式
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
- 分别维护「Demo 状态」与「真实接入状态」。假数据交互完成,不等于接口或正式功能完成。
|
||||
- 状态使用:待实现、进行中、已验证、待接口验证、暂不支持。
|
||||
- 实现后记录文件和函数或元素位置、验收结果;业务口径变化时同步更新规则与变更记录。
|
||||
- 当前范围为优化本地假数据 Demo,不接入账号,不修改原 Python 业务逻辑,不推送。
|
||||
- 当前范围为正式看板接入真实数据;历史 Demo 仅保留交互样例。
|
||||
|
||||
## 已确认业务口径
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 248 KiB |
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 217 KiB |
@@ -2,17 +2,17 @@
|
||||
|
||||
**目标:** 将正式看板的阅读目标迁移到现有 MySQL,保留当前业务规则与浏览器旧数据导入入口。
|
||||
|
||||
**方案:** Flask v2 接口读写 `reading_goals`、`reading_goal_books`,前端仅在服务端确认后更新目标。沿用当前个人看板范围,不增加账户体系。书籍成员独立于书架缓存,完成率根据当前已知阅读状态计算。
|
||||
**方案:** Flask 当前接口读写 `reading_goals`、`reading_goal_books`,前端仅在服务端确认后更新目标。沿用当前个人看板范围,不增加账户体系。书籍成员独立于书架缓存,完成率根据当前已知阅读状态计算。
|
||||
|
||||
**技术栈:** 现有 Flask、PyMySQL、原生 JavaScript,无新增依赖。
|
||||
|
||||
## 步骤与验收
|
||||
|
||||
- [x] 后端:在 `api_v2.py` 增加 GET/POST `/api/v2/goals`、PUT/DELETE `/api/v2/goals/<id>`、POST `/api/v2/goals/import`。JSON 字段沿用 `id/name/start/end/ids/sources`;列表返回 `{goals: [...]}`,写入返回 `{goal: ...}`,导入返回 `{imported: N}`。先补接口失败用例,再实现校验、原子事务、重复导入跳过已有 ID。
|
||||
- [x] 后端:在 `reading_api.py` 增加 GET/POST `/api/reading/goals`、PUT/DELETE `/api/reading/goals/<id>`、POST `/api/reading/goals/import`。JSON 字段沿用 `id/name/start/end/ids/sources`;列表返回 `{goals: [...]}`,写入返回 `{goal: ...}`,导入返回 `{imported: N}`。先补接口失败用例,再实现校验、原子事务、重复导入跳过已有 ID。
|
||||
- [x] 表结构:新增 `migrations/001_reading_goals.sql`,只创建目标与成员两表;成员联合主键去重,仅对目标做级联删除。通过显式迁移应用,不在每次请求时建表。
|
||||
- [x] 前端:在 `static/js/weapi.js` 复用请求封装支持 JSON 写入,在 `static/js/app.js` 接入加载、保存、追加、删除、导入和错误提示。保存中阻止重复提交,失败保留表单;旧 localStorage 不再作为运行时目标来源,也不删除旧备份。
|
||||
- [x] 边界:缺失书籍仍保留 ID 和目标分母,显示“状态待同步”,允许在编辑器移除;书单来源仅保存名称和加入时书目;日期含起止当天,全部读完优先显示已完成。
|
||||
- [x] 文档:同步 `docs/technical-guide.md`、`docs/code-design.md`、`docs/V2_API.md` 及正式页面提示,保留静态 Demo 的独立说明。
|
||||
- [x] 文档:同步 `docs/technical-guide.md`、`docs/code-design.md`、`docs/API.md` 及正式页面提示,保留静态 Demo 的独立说明。
|
||||
- [x] 验证:使用标准库测试验证非法输入、重复 ID、事务回滚与数据库异常;真实 MySQL 验证新建、重读、编辑、导入和删除,仅操作唯一测试 ID。检查 JavaScript 语法并通过浏览器完成新建、刷新、编辑和清理闭环。
|
||||
|
||||
不创建分支、提交或合并。本次工作在已检查的非主分支工作区进行,保留既有未提交改动。
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
这是独立的静态设计 Demo,不调用微信读书接口,不需要 API Key,也不修改现有 Flask 服务、数据采集脚本和 8080 页面。功能与接口的后续实现进度统一维护在 [功能目标清单](feature-checklist.md)。
|
||||
|
||||
该 Demo 定位为 2.0 设计探索。当前提交用于保存探索成果,不代表 2.0 正式发布,也不创建 `v2.0` 标签。
|
||||
该 Demo 是历史设计探索,用于保留早期交互样例,不代表当前正式入口。
|
||||
|
||||
在项目根目录执行:
|
||||
|
||||
@@ -25,7 +25,7 @@ python3 -m http.server 8765 --bind 127.0.0.1 --directory web-demo
|
||||
|
||||
## 保存与数据边界
|
||||
|
||||
目标使用当前来源的 `localStorage` 键 `weread-demo-goals-v2`,主题使用 `weread-demo-theme`。刷新后保留;更换浏览器、地址或端口不会自动迁移;清除网站数据会清除本地目标。
|
||||
目标使用当前来源的 `localStorage` 键 `weread-demo-goals`,主题使用 `weread-demo-theme`。刷新后保留;更换浏览器、地址或端口不会自动迁移;清除网站数据会清除本地目标。
|
||||
|
||||
书单加入目标时保存当前书籍集合,后续不自动跟随书单变化。同一目标内书籍去重,已读完直接计为完成。新增目标必须有名称、有效时间范围和至少一本书。
|
||||
|
||||
@@ -52,9 +52,9 @@ node --check web-demo/demo-data.js
|
||||
|
||||
交互验收记录见 [功能目标清单](feature-checklist.md)。真实 API、鉴权、分页和服务器持久化尚未验证。
|
||||
|
||||
## 与 1.0 的关系
|
||||
## 与旧版的关系
|
||||
|
||||
1.0 继续由根目录的 `app.py`、`fetch_data.py`、`templates/` 和 `static/` 提供,运行在 8080 端口。2.0 探索 Demo 位于 `web-demo/`,两者可以独立预览。
|
||||
旧版仪表盘已归档到 `legacy/classic/`。当前正式看板由根目录的 `app.py`、`fetch_data.py`、`templates/` 和 `static/` 提供;历史设计 Demo 位于 `web-demo/`,两者可以独立预览。
|
||||
|
||||
## 正式看板的紧凑样式
|
||||
|
||||
@@ -64,9 +64,9 @@ node --check web-demo/demo-data.js
|
||||
|
||||
## 正式看板的阅读目标数据库
|
||||
|
||||
正式页面的目标通过 `/api/v2/goals` 保存到 MySQL。浏览器只保留编辑草稿和页面状态,刷新或换浏览器后从同一服务读取目标。上文 `web-demo/` 的本地存储说明仅适用于静态 Demo。
|
||||
正式页面的目标通过 `/api/reading/goals` 保存到 MySQL。浏览器只保留编辑草稿和页面状态,刷新或换浏览器后从同一服务读取目标。上文 `web-demo/` 的本地存储说明仅适用于静态 Demo。
|
||||
|
||||
沿用 `api_v2.py` 的 `WEREAD_DB_HOST`、`WEREAD_DB_PORT`、`WEREAD_DB_USER`、`WEREAD_DB_PASSWORD` 和 `WEREAD_DB_NAME` 配置,不新增依赖。服务仍使用当前个人账号的数据;多个浏览器连接同一服务时共享目标,没有新增多用户隔离。
|
||||
沿用 `reading_api.py` 的 `WEREAD_DB_HOST`、`WEREAD_DB_PORT`、`WEREAD_DB_USER`、`WEREAD_DB_PASSWORD` 和 `WEREAD_DB_NAME` 配置,不新增依赖。服务仍使用当前个人账号的数据;多个浏览器连接同一服务时共享目标,没有新增多用户隔离。
|
||||
|
||||
部署新代码前,在项目根目录执行一次迁移。下面的命令复用服务配置,只创建两张目标表,不修改已有业务表:
|
||||
|
||||
@@ -74,7 +74,7 @@ node --check web-demo/demo-data.js
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import pymysql
|
||||
from api_v2 import MYSQL_CONFIG
|
||||
from reading_api import MYSQL_CONFIG
|
||||
|
||||
with pymysql.connect(**MYSQL_CONFIG) as conn:
|
||||
with conn.cursor() as cur:
|
||||
@@ -125,7 +125,7 @@ DEPLOY_BRANCH=dev ./deploy.sh
|
||||
|
||||
`deploy.sh` 会优先读取项目根目录 `.env`;没有 `.env` 时,会读取 `weread.service` 当前 `Environment=` 配置。按截图中的 service 写法也能拿到端口、API Key 和数据库配置。若以后改用普通部署用户,需要允许该用户免密执行 `systemctl restart weread.service`。
|
||||
|
||||
浏览器旧目标不会自动覆盖数据库。在原访问地址打开“阅读目标”,点击“导入已有目标”;数据库已有同一 ID 时跳过,整批成功才标记导入完成。`weread-goals-v2` 原数据保留,`weread-goals-v2-imported` 只记录已导入。不同浏览器、域名和端口的旧存储需要分别在原地址导入。
|
||||
浏览器旧目标不会自动覆盖数据库。在原访问地址打开“阅读目标”,点击“导入已有目标”;数据库已有同一 ID 时跳过,整批成功才标记导入完成。`weread-goals` 原数据保留,`weread-goals-imported` 只记录已导入。不同浏览器、域名和端口的旧存储需要分别在原地址导入。
|
||||
|
||||
保存失败会保留表单并提示重试;读取失败显示错误和重试按钮,不冒充空列表。若新建提示 ID 已存在,刷新目标列表确认上次请求是否已经保存。数据库不可用或尚未执行迁移时,目标接口返回 503,不退回浏览器保存。
|
||||
|
||||
|
||||