v67:读书模块补齐(书能点进去 / 加一本 / 读书笔记 / 统计)
用户 2026-10-20:「其他的功能也逐步完成……读书点不进去,也没法加书,
设置也没有任何的东西。」
## 先修三处「对着服务端抄错的口径」(都不报错,只是显示是错的)
1. 状态值:服务端 `Book::STATUS` 只有 wish/reading/done/paused,**没有 want**;
`Book::status()` 遇到不认识的值会静默改成 `wish`,而端上分组键写的 `want`
⇒ 书架里「想读」那一组**整组不显示**(页头还数着它,看着像书丢了)。
`paused`(搁置)同样没列 ⇒ 搁置的书也人间蒸发。
2. 评分:服务端 `rating` 是 0–10,端上当 0–5 用 ⇒ 8 分显示成 `8.0/5`。
现在解析时折半、写回时 ×2。
3. 进度:服务端 `progress` 是「读到第几章」,端上当百分比 ⇒ 读到第 30 章 = 30%。
现在按 `chapter_count` 换算,没解析过章节的书不画假进度。
## 补齐三个死掉的入口
- 书行整行可点 → `FbBookSheet`(状态 / 评分 / 章节进度 / 读书笔记 / 删除二次确认)
- 页头「+ 加一本」→ 同一浮层的新建态(书名 / 作者 / 状态)
- 设置「读书统计」→ 端上现算(藏书/在读/读完/想读/搁置/笔记条数);
另两条(导入笔记 / 微信读书)要文件选择与授权,仍标「网页端」,不摆假入口
## 服务端能力边界(照实做)
- `PATCH /books/<id>` 只认 status / rating ⇒ 详情里不给改书名/作者的输入框
- 章节进度只读(`progress` 由阅读器翻页写,接口没有回写入口)
- 读书笔记走真实接口 `GET/POST /books/<id>/notes`
## 验证
- `hvigorw assembleHap` → BUILD SUCCESSFUL
- `_fb_arkts_guard.js` → 797 / 0(新增 groupV67 28 条,含「端上分组键 ==
服务端枚举」的跨语言对照)
- `_fb_v59d_falsify.py` → 130 / 0(v67 新增 13 条注入全部变红)
- ⚠️ 设备仍断连(`hdc list targets` → `[Empty]`),真机未验收
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
FbAccount, FbAnniversaryItem, FbBookItem, FbCalEvent, FbHomeData, FbKinChip,
|
||||
FbAccount, FbAnniversaryItem, FbBookItem, FbBookNoteItem, FbCalEvent, FbHomeData, FbKinChip,
|
||||
FbKinGraph, FbKinPerson, FbMark,
|
||||
FbLedgerBook, FbLedgerDetail, FbLedgerEntry, FbNoteItem, FbNotificationItem, FbResourceItem,
|
||||
FbTaskItem, FbTripItem, FbWeather, FbStat, FbMemoryItem, FbRecentDay,
|
||||
@@ -199,6 +199,15 @@ interface RawBook {
|
||||
id?: number; title?: string; author?: string | null; status?: string | null;
|
||||
rating?: number | null; progress?: number | null; note_count?: number | null;
|
||||
cover_key?: string | null; category?: string | null; publisher?: string | null;
|
||||
/** 共几章(0 = 没解析过章节)。`progress` 是"读到第几章",没有它就没法算百分比 */
|
||||
chapter_count?: number | null;
|
||||
}
|
||||
|
||||
interface RawBookNote {
|
||||
id?: number; kind?: string | null; content?: string | null;
|
||||
chapter?: string | null; loc?: string | null;
|
||||
person_name?: string | null; my_nickname?: string | null;
|
||||
created_at?: string | null;
|
||||
}
|
||||
|
||||
interface RawNote {
|
||||
@@ -507,23 +516,54 @@ export function parseBooks(json: string): FbBookItem[] {
|
||||
const rows: RawBook[] = asArray<RawBook>(json);
|
||||
const out: FbBookItem[] = [];
|
||||
for (const r of rows) {
|
||||
const st: string = s(r.status) !== '' ? s(r.status) : 'want';
|
||||
/* 🔴🔴 v67:回落值必须是 **`wish`**(服务端枚举),原来写的 `want` 服务端不认
|
||||
⇒ `Book::status()` 把不认识的静默改成 `wish`,而端上分组只认 `want`
|
||||
⇒ "想读"的书在书架里一本都看不见。 */
|
||||
const st: string = s(r.status) !== '' ? s(r.status) : 'wish';
|
||||
const chapters: number = n(r.chapter_count);
|
||||
const cur: number = n(r.progress);
|
||||
const it: FbBookItem = {
|
||||
id: n(r.id),
|
||||
title: s(r.title),
|
||||
author: s(r.author),
|
||||
status: st,
|
||||
rate: n(r.rating),
|
||||
/* 🔴 服务端 `rating` 是 0–10(`Book::rating()` 校验 `0 <= n <= 10`),
|
||||
端上 `FbRating` 的 max 是 5 ⇒ 必须折半,否则 8 分显示成 `8.0/5`。 */
|
||||
rate: clamp(n(r.rating) / 2, 0, 5),
|
||||
noteCount: n(r.note_count),
|
||||
// 服务端 progress 记的是"读到第几页"还是"百分比"不确定
|
||||
// ⇒ 只信 status:读完就是 100,否则按 progress 原样(0~100 之外夹紧)
|
||||
progress: st === 'done' ? 100 : clamp(n(r.progress), 0, 100),
|
||||
/* 🔴 `progress` 是**章序号**不是百分比(`Book::setProgress` 注释:读到第几章)
|
||||
⇒ 有 `chapter_count` 才能换算;没解析过章节(=0)就只能是 0,
|
||||
不要拿章序号冒充百分比(读到第 30 章 ≠ 30%)。 */
|
||||
progress: st === 'done' ? 100
|
||||
: (chapters > 0 ? clamp(cur * 100 / chapters, 0, 100) : 0),
|
||||
curChapter: cur,
|
||||
chapters: chapters,
|
||||
};
|
||||
out.push(it);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 读书笔记 → FbBookNoteItem[] */
|
||||
export function parseBookNotes(json: string): FbBookNoteItem[] {
|
||||
const rows: RawBookNote[] = asArray<RawBookNote>(json);
|
||||
const out: FbBookNoteItem[] = [];
|
||||
for (const r of rows) {
|
||||
const nick: string = s(r.my_nickname);
|
||||
out.push({
|
||||
id: n(r.id),
|
||||
kind: s(r.kind) !== '' ? s(r.kind) : 'note',
|
||||
content: s(r.content),
|
||||
chapter: s(r.chapter),
|
||||
loc: s(r.loc),
|
||||
/* 我称呼这个人的名字优先(`nicknames` 二元组),没有再退回他的本名 */
|
||||
personName: nick !== '' ? nick : s(r.person_name),
|
||||
createdAt: s(r.created_at).substring(0, 10),
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 笔记 → FbNoteItem[] */
|
||||
export function parseNotes(json: string): FbNoteItem[] {
|
||||
const root: Record<string, Object> | null = asObject(json);
|
||||
|
||||
Reference in New Issue
Block a user