v0.8.1 界面六条:删离线入口 / 标语统一 / 最近纪念日 / 图标真上色 / 真头像 / 日程四修

用户 2026-10-18 六条(全部已在真机逐条验证):

① 登录页「先不登录 / 离线使用」彻底删除
   用户:「把那些不登录、看离线数据之类的提示全部去掉。以后就不再拥有这样的
   功能了,把这些功能也全部删除。」
   ⇒ 两个按钮 + onSkip + allowSkip 参数 + Index 里的 skip 分支一起删净。
   这是产品决定(不是隐藏):该路径本身就是安全缺口,v58 上了整库加密后更要堵死。

② 标语统一为「一家人用岁月写成的一本书」
   用户:「这也是我们"家书"这个名字的由来。所以你不要再乱换这个标语了,
   只要是想出现标语或者副标题的地方,就用这样一句话。」
   · 端上 FB_DEFAULT_SLOGAN 是唯一定义处(登录页副标题 + 抽屉回落都用它);
   · 抽屉左上角原来是家庭名,现在显示**标语**;
   · 三层优先级(个人 slogan → 家庭 motto → 应用默认口号)**在服务端算**
     (Family::slogan,与网页端首页 heroSlogan 同一套),/login 与 /me 都返回。
   用户还说:「如果这个用户自己有标语……这个地方就是用户自己自定义的标语。」
   真机实测:登录者杨永全自己写了「修身,齐家」⇒ 抽屉就显示他那句。

③ 首页新增「最近纪念日」(放在近期任务之后、往年的今天之前)
   用户:「未来最近的三个纪念日,包括每个人的生日,以及手动填写的各个纪念日。
   以倒计时形式展示:距离哪个纪念日还有多少天,距离谁谁谁的生日还有多少天。」
   · /home.recent_days = Anniversary::upcoming(fam,pid,370) 取前 3 ——
     取满一年:窗口太小会让"刚过完生日"的家庭一个都取不到,模块直接空着;
   · 数据源 all() = 派生生日 + 自建纪念日,正好覆盖用户说的两样;
   · 倒计时:0 天显示「就是今天」(写「还有 0 天」读起来像已经过了)。

④ 悬浮栏图标也上色(用户:「除了下面的汉字,上面图标的颜色也变成跟汉字一样的颜色」)
   🔴🔴 真根因两层,都是"无报错失效":
   · 第一层:Image.fillColor() **只对 SVG 生效**,而本工程 30+ 图标**全是 PNG**
     ⇒ 全工程 24 处图标染色一直是空操作(文字走 fontColor 所以只有文字变了)。
   · 第二层(真机才现形):改用 colorFilter 后,矩阵写成了"系数乘 RGB"
     (R' = R_原 × 系数) —— 对白色图标成立,但本工程图标是**纯黑**,
     黑 × 任何系数 = 仍是黑 ⇒ 真机上图标像素依旧是 (0,0,0)。
   ⇒ 最终形态:`fbTint` 用 **alpha 当载体**(R' = (r/255) × A_原):
     系数是归一化约定(官方灰度示例系数和为 1,量纲确定);
     形状完全由原图 alpha 决定 ⇒ 黑/白图标都成立,描边抗锯齿自然过渡。
   真机像素实测:日程项图标与文字同为 (176,120,64)≈#B0763A;
   未选中项图标 (44,39,35) 深灰(不再是纯黑)。
   ⚠️ 全工程 24 处 fillColor 一并改掉;FbIconButton.tint 类型改成 string,
      让"误传 Resource"变成编译错误而不是又一个静默失效。

⑤ 顶栏:真实头像 + 拉开按钮间距
   用户:「右上角的头像应该是真实的……现在提醒的按钮距离头像的按钮太近了。」
   · /home 给 me_avatar、/login 给 avatar_url(avatar_url() 按线上存储驱动拼好);
   · 三颗按钮(同步 / 铃铛 / 头像)统一用 FbMetric.gapTopActions = 8。

⑥ 日程四处
   · 「日期下面有几个点」⇒ 月视图与周视图的圆点全部删除,
     连 FbDot / dots() / count / dotColor 一起清(不留死代码);
   · 「农历全部都是初一」⇒ 真根因是端上 lunarOf() **硬编码 return '初一'**,
     而服务端 lunarRange() 本来就每天给真实农历(title)⇒ 改取 title;
   · 「列表这个视图,今天的数据缺一条」⇒ 服务端 /calendar 的 from/to **默认只给本月**,
     而列表视图要显示 -7 ~ +60 天 ⇒ 端上显式传范围
     (loadModule 新增 pathOverride 参数);
   · 「点击了某一天之后并不明显,应该把这一天的颜色变深,而今天用一个较浅的颜色」
     ⇒ 照 SyncCalendar:选中 = 深色实底白字、今天 = 浅色底。
       真机实测:17 号(选中)bg=#FFB0763A,18 号(今天)bg=#FFF5F0EA。

另:FbKeyStore 补上一个真机抓到的 HUKS 坑 —— isKeyItemExist 在密钥不存在时
**会抛 12000011**(不是返回 false),首次运行必被误判成"本机不支持 HUKS"
⇒ 永久明文降级。改成把"不存在"当正常分支,且降级态每次启动重试一次
(把同一把 DEK 重新用 KEK 包起来,不换密钥以免重下全部附件)。

验证:hvigor BUILD SUCCESSFUL;_fb_arkts_guard.js 328/0;
_fb_v59ui_falsify.py 19 项注入 23/0;_fb_home_api.py 60/0;
六条已在真机逐条取像素/布局树确认。
This commit is contained in:
2026-10-18 20:14:40 +08:00
parent 2132ee42d2
commit f020a671c0
27 changed files with 862 additions and 221 deletions
+16 -1
View File
@@ -17,6 +17,21 @@ import { FbAccount, FbBookItem, FbCalBook, FbCalEvent, FbGroup,
FbNoteItem, FbNotificationItem, FbResourceItem, FbRosterItem, FbSession,
FbTaskItem, FbTripItem, FbTripNode } from './Types';
/**
* 🔴🔴 应用口号(**唯一**定义处,用户 2026-10-18 明确指定)。
*
* 用户原话:「我们应用的口号或者标语是:**一家人用岁月写成的一本书**。
* 这也是我们"家书"这个名字的由来。所以你不要再乱换这个标语了,
* 只要是想出现标语或者副标题的地方,就用这样一句话。」
*
* ⚠️ **不要再改这句话**,也不要就地另写一个字符串 ——
* 所有需要"标语 / 副标题"的位置都从这里取(登录页、抽屉品牌区…)。
* ⚠️ 它与服务端的 `Family::DEFAULT_SLOGAN` 是**同一句话**:
* 服务端那份在用户填了自己的 slogan 时会返回用户那句(见 `Family::slogan()`),
* 端上这份只是"还没拿到接口数据时"的兜底,以及登录页(此时还没有用户数据)。
*/
export const FB_DEFAULT_SLOGAN: string = '一家人用岁月写成的一本书';
/** 假数据里的「我」 */
export const FB_DEMO_ME: FbAccount = {
id: 1,
@@ -33,7 +48,7 @@ export const FB_DEMO_SESSION: FbSession = {
loggedIn: true,
familyId: 1,
familyTitle: '杨家',
slogan: '记录家庭的全部生活,一本用岁月写成的家谱',
slogan: FB_DEFAULT_SLOGAN,
me: FB_DEMO_ME
};
+50
View File
@@ -25,6 +25,16 @@ export interface FbAccount {
kinship: string;
/** 头像色(Web 端 AvatarColor 算法得出) */
avatarColor: string;
/**
* 🔴 v59(用户 2026-10-18):「右上角的头像应该是真实的」——
* 这里放**真实头像图片的完整 URL**(服务端 `avatar_url()` 给的,
* 空串 = 这个人没传过头像 ⇒ 端上回落成色块字)。
*
* ⚠️ URL 由服务端拼好(它会按线上存储驱动决定走 /uploads 还是 OSS 直链),
* 端上**不要**自己拼路径 —— 拼错了就是"永远破图",而那正是这次要修的观感。
* ⚠️ 可选(`?`):老代码/演示数据没有这一项,`undefined` 等价于空串。
*/
avatarUrl?: string;
/** 角色:admin / member / guest(Web 端 accounts.role) */
role: string;
/** 是否为只读访客(Web 端 Auth::isGuest) */
@@ -171,6 +181,42 @@ export interface FbMemoryItem {
yearsAgo: number;
}
/**
* 🔴 v59(用户 2026-10-18):首页「最近纪念日」里的一条。
*
* 用户原话:「首页应该加一个『最近纪念日』模块,放在『往年的今天』前面、
* 『近期任务』后面。内容包括:
* 1. 未来最近的三个纪念日,包括每个人的生日,以及手动填写的各个纪念日。
* 2. 以倒计时形式展示:距离哪个纪念日还有多少天,距离谁谁谁的生日还有多少天。」
*
* ⇒ 服务端 `/home` 的 `recent_days` 已按"最近的在前"排好、最多 3 条,
* 数据来源是 `Anniversary::occurrences()` → `all()` = **派生生日 + 自建纪念日**,
* 正好一次覆盖用户说的两样。
*/
export interface FbRecentDay {
/** 自建纪念日的 id(派生生日为 0) */
id: number;
/** 下一次发生的日期 `YYYY-MM-DD` */
date: string;
/** 标题(已含姓名,如「老杨 的生日」「结婚纪念日」)—— 直接显示 */
title: string;
/** 类别(用户填的,如「生日」「结婚纪念」) */
kind: string;
/** 关联的人(自建纪念日可能关联多人;0 = 没关联) */
personId: number;
/**
* 来源:`custom` = 手动填的纪念日;`birthday_solar` / `birthday_lunar` = 派生生日。
* ⚠️ 端上据此在文案上区分「纪念日 / 生日」(用户两条要求分别就是这两类)。
*/
source: string;
/** 距今天还有几天(**0 = 就是今天**;服务端保证非负) */
days: number;
/** 周岁(派生生日才有;null = 没有) */
age: number;
/** 是第几个(自建纪念日且填了起始年才有;null = 不显示序号) */
nth: number;
}
/** 首页「模块卡片」—— 一块一块的入口,带一句关键数字 */
export interface FbModuleCard {
/** 模块 key(点击后切到哪个模块) */
@@ -216,6 +262,10 @@ export interface FbHomeData {
stat: FbStat;
/** 往年的今天(与电脑端 `Home::memories()` 同一个逻辑) */
memories: FbMemoryItem[];
/** 🔴 v59:未来最近的三个纪念日(含生日),倒计时用(服务端已排好序) */
recentDays: FbRecentDay[];
/** 🔴 v59:我的真实头像 URL(顶栏右上角用;'' = 没传过头像) */
meAvatar: string;
/** 今天的日程(服务端已排好:全天在前、其余按时间) */
todayEvents: FbCalEvent[];
/** 近期任务(**进行中在前、待办在后**,用户 2026-10-16 要求含待办) */