已读完的书卡改成和「在读」同一套样式,补开始/读完时间
可行性(先说结论)
- 「开始阅读时间」在官方文档里没列,但 /book/getprogress 的原始回包里有
book.startReadingTime,6 本已读完的全都有
- 顺带纠正我上一轮的错误结论:真正常为 0 的是 recordReadingTime,
book.readingTime 是有值的(西线无战事 6190 秒 = 103 分),
已存进 JSON 的 readingSeconds,卡片暂未展示
抽公共组件
- 新增 src/components/reading-card.astro,在读和已读完共用,样式强制统一:
横版卡片、封面在左、信息在右
- 两处只在底部两行不同:
在读 进度条 + 百分比 / 最近阅读 X
已读完 开始 X / 读完 Y(无进度条)
数据层
- fetch-reading.mjs 每个条目新增 startedAt / finishedAt / readingSeconds
- src/lib/reading.ts 的 ReadingBook 类型同步补上(都可选,老数据不会炸)
- startReadingTime / finishTime 缺失时卡片自动少一行,不会渲染出「开始 —」
时间显示走 Asia/Shanghai。所以西线无战事的 startReadingTime
1786207913(UTC 08-08T15:31Z)在页面上是「开始 2026-08-09」,
这才是本地日期。
静态验证(dist/bookshelf/index.html)
- 在读区 20 张卡 / 20 条进度条 / 20 个「最近阅读」
- 已读完区 6 张卡 / 0 条进度条 / 6 个「开始 X」/ 6 个「读完 X」
- 抽一张:西线无战事(译文经典) 雷马克 · 文学-外国文学
开始 2026-08-09 读完 2026-09-06,确认不含进度条
- 搜索/领域筛选的 data-weread-card 仍挂在新卡片上,筛选不受影响
This commit is contained in:
@@ -297,7 +297,8 @@ src/components/bookshelf-content.astro
|
|||||||
- 请求体里 `skill_version` **必填**,业务参数**平铺在顶层**,不能包进 `params`
|
- 请求体里 `skill_version` **必填**,业务参数**平铺在顶层**,不能包进 `params`
|
||||||
- `/shelf/sync` 一次就给全封面/书名/作者/分类/最近阅读时间/跳转链接,**只有阅读进度**要额外调 `/book/getprogress`,所以请求数 = 1 + N
|
- `/shelf/sync` 一次就给全封面/书名/作者/分类/最近阅读时间/跳转链接,**只有阅读进度**要额外调 `/book/getprogress`,所以请求数 = 1 + N
|
||||||
- `book.progress` 是 0–100 的整数,**只有 100 才算读完**
|
- `book.progress` 是 0–100 的整数,**只有 100 才算读完**
|
||||||
- `book.recordReadingTime` **恒为 0**,所以卡片不做「累计时长」
|
- `book.recordReadingTime` **恒为 0**(别用它),但 `book.readingTime` 是真数据,累计时长取后者(已存进 JSON 的 `readingSeconds`,卡片暂未展示)
|
||||||
|
- `book.startReadingTime` **官方文档没列,但回包里确实有**,就是「开始阅读时间」;只有 readUpdateTime 那 26 本里有 8 本没有它(基本都是没怎么打开的书)
|
||||||
- `deepLink` 实测是普通 https(`https://weread.qq.com/book-detail?...`),浏览器能直接打开
|
- `deepLink` 实测是普通 https(`https://weread.qq.com/book-detail?...`),浏览器能直接打开
|
||||||
- `category` 是 `文学-外国文学` 这种「大类-子类」复合串
|
- `category` 是 `文学-外国文学` 这种「大类-子类」复合串
|
||||||
- 时间戳统一按 `YYYY-MM-DD` 展示(官方硬性要求),顺带避开「N 天前」在静态站上会随构建时间变旧
|
- 时间戳统一按 `YYYY-MM-DD` 展示(官方硬性要求),顺带避开「N 天前」在静态站上会随构建时间变旧
|
||||||
@@ -309,7 +310,14 @@ src/components/bookshelf-content.astro
|
|||||||
| 最近在读 | `progress < 100`(含 0%,标「还没开始」) |
|
| 最近在读 | `progress < 100`(含 0%,标「还没开始」) |
|
||||||
| 书籍 → 「微信读书 · 已读完」分组 | `progress === 100` |
|
| 书籍 → 「微信读书 · 已读完」分组 | `progress === 100` |
|
||||||
|
|
||||||
这一组混在「书籍」区的网格里,卡片结构和手工书单一致,但没有书评/简介,所以点击是直接跳微信读书而不是弹窗。它们带 `data-weread-card` 和 `data-category="微信读书"`,所以搜索框和「领域」筛选同样作用得到(领域里会多出一个「微信读书」选项)。过滤掉的:私密阅读(`secret === 1`)、从没打开过的书;有声书不处理。
|
**两处用的是同一个组件 `src/components/reading-card.astro`**,保证样式统一 —— 横版卡片、封面在左、信息在右,只有底部两行不同:
|
||||||
|
|
||||||
|
| | 第 1 行 | 第 2 行 |
|
||||||
|
|---|---|---|
|
||||||
|
| 在读 | 进度条 + 百分比 | 最近阅读 X |
|
||||||
|
| 已读完 | 开始 X | 读完 Y |
|
||||||
|
|
||||||
|
「已读完」那一组混在「书籍」区里,但没有书评/简介,所以点击直接跳微信读书而不是弹窗。它们带 `data-weread-card` 和 `data-category="微信读书"`,所以搜索框和「领域」筛选同样作用得到(领域里会多出一个「微信读书」选项)。过滤掉的:私密阅读(`secret === 1`)、从没打开过的书;有声书不处理。
|
||||||
|
|
||||||
**2. 书籍** —— 来自 `public/data/books.json`,由 `bookshelf-content.astro` 在构建时 import(文件必须存在)。另外两个文件 `papers.json` / `comics.json` 对应的漫画、论文分类已经移除,文件保留但不再被引用。
|
**2. 书籍** —— 来自 `public/data/books.json`,由 `bookshelf-content.astro` 在构建时 import(文件必须存在)。另外两个文件 `papers.json` / `comics.json` 对应的漫画、论文分类已经移除,文件保留但不再被引用。
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
* 两处实测得到的结论,别被直觉带偏:
|
* 两处实测得到的结论,别被直觉带偏:
|
||||||
* 1. /shelf/sync 一次就给全了封面/书名/作者/分类/最近阅读时间/跳转链接,
|
* 1. /shelf/sync 一次就给全了封面/书名/作者/分类/最近阅读时间/跳转链接,
|
||||||
* 只有「阅读进度」要额外调 /book/getprogress,所以请求数 = 1 + N
|
* 只有「阅读进度」要额外调 /book/getprogress,所以请求数 = 1 + N
|
||||||
* 2. book.recordReadingTime 恒为 0,拿不到累计时长,所以卡片不做这一项
|
* 2. book.recordReadingTime 恒为 0,但 book.readingTime 是真数据,累计时长取后者
|
||||||
|
* 3. 官方文档没列 book.startReadingTime,但回包里有,是「开始阅读时间」
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from "node:fs"
|
import fs from "node:fs"
|
||||||
@@ -104,6 +105,12 @@ async function fetchReading() {
|
|||||||
progress: null,
|
progress: null,
|
||||||
finished: false,
|
finished: false,
|
||||||
lastReadAt: new Date(Number(book.readUpdateTime) * 1000).toISOString(),
|
lastReadAt: new Date(Number(book.readUpdateTime) * 1000).toISOString(),
|
||||||
|
// 下面三个来自 /book/getprogress。官方文档没列 startReadingTime,
|
||||||
|
// 但原始回包里确实有(读完的 6 本全都有),是「开始阅读时间」。
|
||||||
|
startedAt: null,
|
||||||
|
finishedAt: null,
|
||||||
|
/** 累计阅读秒数。注意是 readingTime,不是恒为 0 的 recordReadingTime */
|
||||||
|
readingSeconds: null,
|
||||||
deepLink: book.deepLink ?? "",
|
deepLink: book.deepLink ?? "",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +122,15 @@ async function fetchReading() {
|
|||||||
// progress 是 0-100 的整数,只有正好 100 才算读完
|
// progress 是 0-100 的整数,只有正好 100 才算读完
|
||||||
entry.finished = reading.progress === 100
|
entry.finished = reading.progress === 100
|
||||||
}
|
}
|
||||||
|
if (reading.startReadingTime) {
|
||||||
|
entry.startedAt = new Date(reading.startReadingTime * 1000).toISOString()
|
||||||
|
}
|
||||||
|
if (reading.finishTime) {
|
||||||
|
entry.finishedAt = new Date(reading.finishTime * 1000).toISOString()
|
||||||
|
}
|
||||||
|
if (typeof reading.readingTime === "number") {
|
||||||
|
entry.readingSeconds = reading.readingTime
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 单本节失败不该让整次抓取挂掉,卡片退化成「不显示进度条」
|
// 单本节失败不该让整次抓取挂掉,卡片退化成「不显示进度条」
|
||||||
console.warn(` ⚠️ ${book.title}:进度获取失败 — ${error.message}`)
|
console.warn(` ⚠️ ${book.title}:进度获取失败 — ${error.message}`)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import SiteHeader from "@/components/site-header.astro"
|
|||||||
import Footer from "@/components/footer.astro"
|
import Footer from "@/components/footer.astro"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import booksData from "../../public/data/books.json"
|
import booksData from "../../public/data/books.json"
|
||||||
|
import ReadingCard from "@/components/reading-card.astro"
|
||||||
import { formatReadingDate, getReadingData } from "@/lib/reading"
|
import { formatReadingDate, getReadingData } from "@/lib/reading"
|
||||||
|
|
||||||
// 微信读书数据。数据缺失时 reading 为 null,页面退化成空态,不报错。
|
// 微信读书数据。数据缺失时 reading 为 null,页面退化成空态,不报错。
|
||||||
@@ -160,59 +161,7 @@ const recommendBadge = (status?: string) => {
|
|||||||
|
|
||||||
{inProgressReading.length > 0 ? (
|
{inProgressReading.length > 0 ? (
|
||||||
<div class="grid gap-4 sm:grid-cols-2">
|
<div class="grid gap-4 sm:grid-cols-2">
|
||||||
{inProgressReading.map((book) => (
|
{inProgressReading.map((book) => <ReadingCard book={book} />)}
|
||||||
<a
|
|
||||||
href={book.deepLink || undefined}
|
|
||||||
target={book.deepLink ? "_blank" : undefined}
|
|
||||||
rel={book.deepLink ? "noopener noreferrer" : undefined}
|
|
||||||
class="group flex gap-4 rounded-xl border border-border/50 bg-card p-4 transition-shadow duration-300 hover:shadow-lg"
|
|
||||||
>
|
|
||||||
<div class="shrink-0 w-20 aspect-[3/4] rounded-lg overflow-hidden bg-surface-subtle">
|
|
||||||
{book.cover ? (
|
|
||||||
<img
|
|
||||||
src={book.cover}
|
|
||||||
alt={book.title}
|
|
||||||
loading="lazy"
|
|
||||||
decoding="async"
|
|
||||||
referrerpolicy="no-referrer"
|
|
||||||
class="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div class="flex h-full w-full items-center justify-center p-2 bg-gradient-to-br from-primary/30 via-primary/20 to-primary/5">
|
|
||||||
<p class="font-semibold text-[10px] text-foreground text-center line-clamp-4">{book.title}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-1 min-w-0 flex flex-col">
|
|
||||||
<h3 class="font-medium text-sm text-foreground line-clamp-2 leading-snug mb-1 group-hover:text-primary transition-colors">
|
|
||||||
{book.title}
|
|
||||||
</h3>
|
|
||||||
<p class="text-xs text-muted-foreground line-clamp-1 mb-3">
|
|
||||||
{[book.author, book.category].filter(Boolean).join(" · ")}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="mt-auto space-y-1.5">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<div class="flex-1 h-1.5 rounded-full bg-secondary overflow-hidden">
|
|
||||||
<div class="h-full rounded-full bg-primary" style={`width: ${book.progress ?? 0}%`} />
|
|
||||||
</div>
|
|
||||||
<span
|
|
||||||
class={cn(
|
|
||||||
"text-[11px] tabular-nums shrink-0",
|
|
||||||
book.finished ? "text-status-positive-fg font-medium" : "text-muted-foreground",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{book.finished ? "已读完" : !book.progress ? "还没开始" : `${book.progress}%`}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<p class="text-[11px] text-muted-foreground/80 tabular-nums">
|
|
||||||
最近阅读 {formatReadingDate(book.lastReadAt)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div class="py-12 text-center border border-dashed border-border rounded-xl">
|
<div class="py-12 text-center border border-dashed border-border rounded-xl">
|
||||||
@@ -361,7 +310,7 @@ const recommendBadge = (status?: string) => {
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
{/* 微信读书里已读完的书,并入「书籍」区。
|
{/* 微信读书里已读完的书,并入「书籍」区。
|
||||||
卡片结构和上面的书一样,但没有书评/简介,所以点击直接跳微信读书,不弹窗。
|
卡片用和「最近在读」同一个 ReadingCard 组件,只是底部换成「开始/读完」两行、没有进度条。
|
||||||
data-weread-card 让搜索框和领域/评价筛选同样作用于这一组。 */}
|
data-weread-card 让搜索框和领域/评价筛选同样作用于这一组。 */}
|
||||||
{finishedReading.length > 0 && (
|
{finishedReading.length > 0 && (
|
||||||
<section data-books-section={WEREAD_CATEGORY}>
|
<section data-books-section={WEREAD_CATEGORY}>
|
||||||
@@ -370,48 +319,20 @@ const recommendBadge = (status?: string) => {
|
|||||||
<span class="text-xs text-muted-foreground" data-books-count>({finishedReading.length})</span>
|
<span class="text-xs text-muted-foreground" data-books-count>({finishedReading.length})</span>
|
||||||
<div class="flex-1 h-px bg-border/60" />
|
<div class="flex-1 h-px bg-border/60" />
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-5">
|
<div class="grid gap-4 sm:grid-cols-2">
|
||||||
{finishedReading.map((book) => (
|
{finishedReading.map((book) => (
|
||||||
<a
|
<ReadingCard
|
||||||
href={book.deepLink || undefined}
|
book={book}
|
||||||
target={book.deepLink ? "_blank" : undefined}
|
attrs={{
|
||||||
rel={book.deepLink ? "noopener noreferrer" : undefined}
|
"data-weread-card": "",
|
||||||
data-weread-card
|
"data-category": WEREAD_CATEGORY,
|
||||||
data-category={WEREAD_CATEGORY}
|
"data-title": book.title.toLowerCase(),
|
||||||
data-title={book.title.toLowerCase()}
|
"data-authors": book.author.toLowerCase(),
|
||||||
data-authors={book.author.toLowerCase()}
|
}}
|
||||||
class="group block cursor-pointer focus:outline-none"
|
/>
|
||||||
>
|
|
||||||
<div class="relative aspect-[3/4] rounded-lg overflow-hidden mb-3 bg-surface-subtle shadow-sm group-hover:shadow-xl transition-shadow duration-300">
|
|
||||||
{book.cover ? (
|
|
||||||
<img
|
|
||||||
src={book.cover}
|
|
||||||
alt={book.title}
|
|
||||||
loading="lazy"
|
|
||||||
decoding="async"
|
|
||||||
referrerpolicy="no-referrer"
|
|
||||||
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div class="flex h-full w-full items-center justify-center p-3 bg-gradient-to-br from-primary/30 via-primary/20 to-primary/5">
|
|
||||||
<p class="font-semibold text-xs text-foreground text-center line-clamp-4">{book.title}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<span class="absolute top-2 right-2 text-[10px] px-2 py-0.5 rounded-full bg-status-positive-bg text-status-positive-fg font-medium">
|
|
||||||
已读完
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="min-h-[3.5rem] space-y-1">
|
|
||||||
<h4 class="font-medium text-sm text-foreground line-clamp-2 group-hover:text-primary transition-colors leading-snug">
|
|
||||||
{book.title}
|
|
||||||
</h4>
|
|
||||||
<p class="text-xs text-muted-foreground line-clamp-1">
|
|
||||||
{[book.author, book.category].filter(Boolean).join(" · ")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
import { formatReadingDate, type ReadingBook } from "@/lib/reading"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信读书书卡。在读和已读完共用同一个组件,保证样式统一 ——
|
||||||
|
* 两者只在底部那两行不同:
|
||||||
|
* 在读 → 进度条 + 百分比 / 「最近阅读 X」
|
||||||
|
* 已读完 → 「开始 X」/「读完 Y」(没有进度条)
|
||||||
|
*/
|
||||||
|
interface Props {
|
||||||
|
book: ReadingBook
|
||||||
|
/** 额外挂在 <a> 上的属性,比如给搜索/筛选用的 data-* */
|
||||||
|
attrs?: Record<string, string | undefined>
|
||||||
|
}
|
||||||
|
|
||||||
|
const { book, attrs = {} } = Astro.props
|
||||||
|
|
||||||
|
const startedText = formatReadingDate(book.startedAt)
|
||||||
|
const finishedText = formatReadingDate(book.finishedAt)
|
||||||
|
---
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={book.deepLink || undefined}
|
||||||
|
target={book.deepLink ? "_blank" : undefined}
|
||||||
|
rel={book.deepLink ? "noopener noreferrer" : undefined}
|
||||||
|
{...attrs}
|
||||||
|
class="group flex gap-4 rounded-xl border border-border/50 bg-card p-4 transition-shadow duration-300 hover:shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="shrink-0 w-20 aspect-[3/4] rounded-lg overflow-hidden bg-surface-subtle">
|
||||||
|
{book.cover ? (
|
||||||
|
<img
|
||||||
|
src={book.cover}
|
||||||
|
alt={book.title}
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
class="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div class="flex h-full w-full items-center justify-center p-2 bg-gradient-to-br from-primary/30 via-primary/20 to-primary/5">
|
||||||
|
<p class="font-semibold text-[10px] text-foreground text-center line-clamp-4">{book.title}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1 min-w-0 flex flex-col">
|
||||||
|
<h3 class="font-medium text-sm text-foreground line-clamp-2 leading-snug mb-1 group-hover:text-primary transition-colors">
|
||||||
|
{book.title}
|
||||||
|
</h3>
|
||||||
|
<p class="text-xs text-muted-foreground line-clamp-1 mb-3">
|
||||||
|
{[book.author, book.category].filter(Boolean).join(" · ")}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-auto space-y-1.5">
|
||||||
|
{book.finished ? (
|
||||||
|
<>
|
||||||
|
{startedText && (
|
||||||
|
<p class="text-[11px] text-muted-foreground/80 tabular-nums">开始 {startedText}</p>
|
||||||
|
)}
|
||||||
|
<p class="text-[11px] text-status-positive-fg font-medium tabular-nums">
|
||||||
|
读完 {finishedText || "—"}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="flex-1 h-1.5 rounded-full bg-secondary overflow-hidden">
|
||||||
|
<div class="h-full rounded-full bg-primary" style={`width: ${book.progress ?? 0}%`} />
|
||||||
|
</div>
|
||||||
|
<span class="text-[11px] tabular-nums shrink-0 text-muted-foreground">
|
||||||
|
{!book.progress ? "还没开始" : `${book.progress}%`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-[11px] text-muted-foreground/80 tabular-nums">
|
||||||
|
最近阅读 {formatReadingDate(book.lastReadAt)}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
+79
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"updatedAt": "2026-09-15T02:45:18.862Z",
|
"updatedAt": "2026-09-15T02:51:38.693Z",
|
||||||
"source": "weread",
|
"source": "weread",
|
||||||
"books": [
|
"books": [
|
||||||
{
|
{
|
||||||
@@ -11,6 +11,9 @@
|
|||||||
"progress": 30,
|
"progress": 30,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-09-13T15:08:26.000Z",
|
"lastReadAt": "2026-09-13T15:08:26.000Z",
|
||||||
|
"startedAt": "2026-09-04T16:07:07.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 4030,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=34c329807197141b34cf1db"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=34c329807197141b34cf1db"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -22,6 +25,9 @@
|
|||||||
"progress": 0,
|
"progress": 0,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-09-09T05:05:04.000Z",
|
"lastReadAt": "2026-09-09T05:05:04.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 20,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=bbc32a50813ab7953g01522a"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=bbc32a50813ab7953g01522a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -33,6 +39,9 @@
|
|||||||
"progress": 77,
|
"progress": 77,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-09-07T09:27:28.000Z",
|
"lastReadAt": "2026-09-07T09:27:28.000Z",
|
||||||
|
"startedAt": "2026-06-03T15:44:54.000Z",
|
||||||
|
"finishedAt": "2026-06-09T11:02:09.000Z",
|
||||||
|
"readingSeconds": 2021,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=de6321e0813abab86g01378d"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=de6321e0813abab86g01378d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -44,6 +53,9 @@
|
|||||||
"progress": 100,
|
"progress": 100,
|
||||||
"finished": true,
|
"finished": true,
|
||||||
"lastReadAt": "2026-09-06T09:45:42.000Z",
|
"lastReadAt": "2026-09-06T09:45:42.000Z",
|
||||||
|
"startedAt": "2026-08-08T16:51:53.000Z",
|
||||||
|
"finishedAt": "2026-09-06T05:26:12.000Z",
|
||||||
|
"readingSeconds": 6190,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=a1932750813ab6e79g017e78"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=a1932750813ab6e79g017e78"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -55,6 +67,9 @@
|
|||||||
"progress": 28,
|
"progress": 28,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-09-06T05:26:38.000Z",
|
"lastReadAt": "2026-09-06T05:26:38.000Z",
|
||||||
|
"startedAt": "2026-08-05T16:49:22.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 7639,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=80a324f0716b1a6480af682"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=80a324f0716b1a6480af682"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -66,6 +81,9 @@
|
|||||||
"progress": 13,
|
"progress": 13,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-06-15T16:24:59.000Z",
|
"lastReadAt": "2026-06-15T16:24:59.000Z",
|
||||||
|
"startedAt": "2026-06-05T15:43:45.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 589,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=b4432330813abb059g01728a"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=b4432330813abb059g01728a"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -77,6 +95,9 @@
|
|||||||
"progress": 97,
|
"progress": 97,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-06-10T16:14:02.000Z",
|
"lastReadAt": "2026-06-10T16:14:02.000Z",
|
||||||
|
"startedAt": "2026-04-17T15:59:58.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 14309,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=140329d0716ce81f140468e"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=140329d0716ce81f140468e"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -88,6 +109,9 @@
|
|||||||
"progress": 0,
|
"progress": 0,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-06-10T16:13:58.000Z",
|
"lastReadAt": "2026-06-10T16:13:58.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 89,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=32f329e0813aba1d3g018fee"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=32f329e0813aba1d3g018fee"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -99,6 +123,9 @@
|
|||||||
"progress": 100,
|
"progress": 100,
|
||||||
"finished": true,
|
"finished": true,
|
||||||
"lastReadAt": "2026-06-07T10:50:15.000Z",
|
"lastReadAt": "2026-06-07T10:50:15.000Z",
|
||||||
|
"startedAt": "2026-05-24T13:35:18.000Z",
|
||||||
|
"finishedAt": "2026-06-06T16:01:25.000Z",
|
||||||
|
"readingSeconds": 7391,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=fb8320d0813ab7b86g01401c"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=fb8320d0813ab7b86g01401c"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -110,6 +137,9 @@
|
|||||||
"progress": 5,
|
"progress": 5,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-06-07T05:15:01.000Z",
|
"lastReadAt": "2026-06-07T05:15:01.000Z",
|
||||||
|
"startedAt": "2026-05-06T23:27:18.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 303,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=ec0325c0813ab718cg017a62"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=ec0325c0813ab718cg017a62"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -121,6 +151,9 @@
|
|||||||
"progress": 16,
|
"progress": 16,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-06-06T18:14:57.000Z",
|
"lastReadAt": "2026-06-06T18:14:57.000Z",
|
||||||
|
"startedAt": "2026-05-02T08:55:25.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 1591,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=ec332c80813abb519g019b32"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=ec332c80813abb519g019b32"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -132,6 +165,9 @@
|
|||||||
"progress": 3,
|
"progress": 3,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-06-01T17:12:29.000Z",
|
"lastReadAt": "2026-06-01T17:12:29.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 106,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=da032ef072517ae3da039f2"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=da032ef072517ae3da039f2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -143,6 +179,9 @@
|
|||||||
"progress": 10,
|
"progress": 10,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-05-13T00:11:25.000Z",
|
"lastReadAt": "2026-05-13T00:11:25.000Z",
|
||||||
|
"startedAt": "2025-01-07T10:42:41.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 1321,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=a3d32d20719debdba3d5de1"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=a3d32d20719debdba3d5de1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -154,6 +193,9 @@
|
|||||||
"progress": 1,
|
"progress": 1,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-04-19T15:00:03.000Z",
|
"lastReadAt": "2026-04-19T15:00:03.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 291,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=7c632ef05a49197c62b53f0"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=7c632ef05a49197c62b53f0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -165,6 +207,9 @@
|
|||||||
"progress": 4,
|
"progress": 4,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-04-18T15:44:35.000Z",
|
"lastReadAt": "2026-04-18T15:44:35.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 160,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=93d325a0719b200493d5ba9"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=93d325a0719b200493d5ba9"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -176,6 +221,9 @@
|
|||||||
"progress": 13,
|
"progress": 13,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-03-28T10:03:33.000Z",
|
"lastReadAt": "2026-03-28T10:03:33.000Z",
|
||||||
|
"startedAt": "2024-12-21T00:52:19.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 2916,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=2a332d10726332f72a34943"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=2a332d10726332f72a34943"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -187,6 +235,9 @@
|
|||||||
"progress": 100,
|
"progress": 100,
|
||||||
"finished": true,
|
"finished": true,
|
||||||
"lastReadAt": "2026-03-28T10:01:44.000Z",
|
"lastReadAt": "2026-03-28T10:01:44.000Z",
|
||||||
|
"startedAt": "2026-03-20T14:42:26.000Z",
|
||||||
|
"finishedAt": "2026-03-22T16:49:18.000Z",
|
||||||
|
"readingSeconds": 15371,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=6d232640727324446d2e978"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=6d232640727324446d2e978"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -198,6 +249,9 @@
|
|||||||
"progress": 100,
|
"progress": 100,
|
||||||
"finished": true,
|
"finished": true,
|
||||||
"lastReadAt": "2026-03-25T17:32:16.000Z",
|
"lastReadAt": "2026-03-25T17:32:16.000Z",
|
||||||
|
"startedAt": "2026-03-23T09:59:40.000Z",
|
||||||
|
"finishedAt": "2026-03-25T17:30:10.000Z",
|
||||||
|
"readingSeconds": 4246,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=8033247071e0e1808035ab9"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=8033247071e0e1808035ab9"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -209,6 +263,9 @@
|
|||||||
"progress": 4,
|
"progress": 4,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2026-01-11T10:35:21.000Z",
|
"lastReadAt": "2026-01-11T10:35:21.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 196,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=b0b32630813abaadeg0157d1"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=b0b32630813abaadeg0157d1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -220,6 +277,9 @@
|
|||||||
"progress": 0,
|
"progress": 0,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2025-10-29T00:43:47.000Z",
|
"lastReadAt": "2025-10-29T00:43:47.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 272,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=5d332c2072575dbf5d33fe2"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=5d332c2072575dbf5d33fe2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -231,6 +291,9 @@
|
|||||||
"progress": 100,
|
"progress": 100,
|
||||||
"finished": true,
|
"finished": true,
|
||||||
"lastReadAt": "2025-10-29T00:43:35.000Z",
|
"lastReadAt": "2025-10-29T00:43:35.000Z",
|
||||||
|
"startedAt": "2019-07-19T04:20:51.000Z",
|
||||||
|
"finishedAt": "2019-07-24T05:23:50.000Z",
|
||||||
|
"readingSeconds": 7718,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=4e3321805b01d74e3fa7481"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=4e3321805b01d74e3fa7481"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -242,6 +305,9 @@
|
|||||||
"progress": 1,
|
"progress": 1,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2025-10-18T09:21:26.000Z",
|
"lastReadAt": "2025-10-18T09:21:26.000Z",
|
||||||
|
"startedAt": "2025-03-26T09:48:02.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 611,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=2bb32ff0813ab6ffcg014315"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=2bb32ff0813ab6ffcg014315"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -253,6 +319,9 @@
|
|||||||
"progress": 10,
|
"progress": 10,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2024-12-21T00:51:54.000Z",
|
"lastReadAt": "2024-12-21T00:51:54.000Z",
|
||||||
|
"startedAt": "2024-12-17T04:42:59.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 549,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=2c032e80813ab95aag019524"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=2c032e80813ab95aag019524"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -264,6 +333,9 @@
|
|||||||
"progress": 6,
|
"progress": 6,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2020-04-09T07:29:49.000Z",
|
"lastReadAt": "2020-04-09T07:29:49.000Z",
|
||||||
|
"startedAt": "2020-04-09T07:23:34.000Z",
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 728,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=814322405a4585814beb03d"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=814322405a4585814beb03d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -275,6 +347,9 @@
|
|||||||
"progress": 100,
|
"progress": 100,
|
||||||
"finished": true,
|
"finished": true,
|
||||||
"lastReadAt": "2019-10-15T15:30:42.000Z",
|
"lastReadAt": "2019-10-15T15:30:42.000Z",
|
||||||
|
"startedAt": "2019-08-07T02:20:48.000Z",
|
||||||
|
"finishedAt": "2019-08-07T07:41:59.000Z",
|
||||||
|
"readingSeconds": 7494,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=770328405c5160770c987ae"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=770328405c5160770c987ae"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -286,6 +361,9 @@
|
|||||||
"progress": 0,
|
"progress": 0,
|
||||||
"finished": false,
|
"finished": false,
|
||||||
"lastReadAt": "2017-05-30T00:49:56.000Z",
|
"lastReadAt": "2017-05-30T00:49:56.000Z",
|
||||||
|
"startedAt": null,
|
||||||
|
"finishedAt": null,
|
||||||
|
"readingSeconds": 137,
|
||||||
"deepLink": "https://weread.qq.com/book-detail?type=1&v=47532ac05c659b47554a825"
|
"deepLink": "https://weread.qq.com/book-detail?type=1&v=47532ac05c659b47554a825"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
+7
-1
@@ -20,8 +20,14 @@ export type ReadingBook = {
|
|||||||
/** 0-100 的整数;null 表示这次没取到进度(单本失败) */
|
/** 0-100 的整数;null 表示这次没取到进度(单本失败) */
|
||||||
progress: number | null
|
progress: number | null
|
||||||
finished: boolean
|
finished: boolean
|
||||||
/** ISO 字符串 */
|
/** 最近一次阅读时间,ISO 字符串 */
|
||||||
lastReadAt: string
|
lastReadAt: string
|
||||||
|
/** 开始阅读时间,ISO;部分书没有这个字段 */
|
||||||
|
startedAt?: string | null
|
||||||
|
/** 读完时间,ISO;只有读完的书才有 */
|
||||||
|
finishedAt?: string | null
|
||||||
|
/** 累计阅读秒数 */
|
||||||
|
readingSeconds?: number | null
|
||||||
/** 微信读书的跳转链接,实测是普通 https,浏览器能直接打开 */
|
/** 微信读书的跳转链接,实测是普通 https,浏览器能直接打开 */
|
||||||
deepLink: string
|
deepLink: string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user