Commit Graph
12 Commits
Author SHA1 Message Date
laoyang 0c2cf9b5e7 表单规范全量铺开 + 编辑时视频附件不显示 (#56)
① 编辑行程的视频附件不显示

根因:照片墙对所有附件都用 Image 渲染,视频是 .mp4,
Image 加载不出来 ⇒ 空白块 ⇒ 用户以为"视频没带进来"。
按 mime 分流:video/ → 深色底 + ▶(不取首帧,端上解视频首帧很卡)。

② 新增共享组件 FbFormField.ets(GLOBAL-FORM-SPEC)

5 个表单原来各写一份 field()/labelRow(),改一处要改五处,
而且外层结构不一致(有的 Row 有的 Column),批量脚本改坏过两次。
收敛到一个组件,表单只调用不自己实现。

③ 全量铺开

- FbPersonEditSheet  姓名标必填(红色无星号)
- FbEventEditSheet   日程 field 两排
- FbMovieNewSheet    片名/影院/同看的人/海报/观影照片/简介/备注 全部两排
- FbDateTimeField    FbDateTimeRow 改两排(电影+日程同时生效)

规范:标签主题色 + Bold + fontSmall,必填红 #C0533F 无星号,
标签独占第一排、控件第二排整宽。
2026-11-05 12:52:51 +08:00
laoyang 5661312679 日程编辑:确认「开始」后结束时间自动 = 开始 + 1 小时 (laoyang/FamilyBook#34)
用户 2026-11-01:
  「当我选择了开始时间并确定之后,结束时间要跟着开始时间变成开始时间加1个小时。
    也就是说,所有时间我们都默认它是一个小时。如果不是一个小时,再让他自己去改。」

## 改前

`applyPicker()` 只在**会变成负时长**时才动结束时间:

    if (this.fEndDate < iso || (this.fEndDate === iso && this.fEndTime < hm)) { ... }

⇒ 用户改了开始、结束还挂在老位置,实际时长变成随机的。

## 改后

点「开始」确定 ⇒ 结束**无条件**重置为「开始 + 1 小时」。
改「结束」那条路一个字不动(改结束不影响开始)—— 这是「默认一小时、
不像一小时再自己改」的另一半。

全天日程跳过这段:时刻部分本来就不生效,改了不会落到服务端,
但会让"切回非全天"时看到一个莫名的时间。

## 新增 fbPlusHours()

`FbDateTimeField.ets` 里加 `fbPlusHours(date, time, hours)`,返回 `{date, time}`。
**不复用现成的 `fbAddHour()`**,因为那个有两个问题:

    return fbPad2(Math.min(hh + 1, 23)) + ':' + mm;

① `Math.min(hh+1, 23)` **封顶 23 点** ⇒ 23:30 加一小时还是 23:30;
② 只返回时间、不带日期 ⇒ 表达不了「次日 00:30」。

跨天/跨月/跨年全部交给 `Date` 运算,不自己算天数
(自己 `if (hh>=24) dd+=1` 在"11 月 30 日 + 1 天"上就会错成 11 月 31 日)。

## 验证

**纯函数真值表 13 项**(从真实 `.ets` 抽函数、只擦类型标注后 node 直接跑,
不手抄替身;擦除后断言行数不变、无类型残留、没引入新字符):

普通 / 跨天整点 / 跨天半点 / 跨月 / 跨年 / 非闰年 2 月末 / **闰年 2 月末 ⇒ 2/29** / 午夜 / 带分钟
—— 全过。其中 23:30+1h ⇒ **次日 00:30**、12/31 ⇒ 次年 01/01、2028-02-28 ⇒ 2028-02-29。

**反向验证 3 项**(证明判据不是恒真):
坏A(封顶 23 点 / 不带日期)被抓到、坏B(丢分钟)被抓到、坏C(固定 28 天)被抓到。

**接线断言 12 项 + 反向验证 5 项**(静态,因为"函数对 ≠ 接进去了",
上一轮 #34 主体 bug 就是参数名对不上、编译运行都不报错):
- 开始分支调用 `fbPlusHours(iso, hm, 1)`、结果**同时**写 `fEndDate` 与 `fEndTime`
- 结束分支**没有任何** `fStart*` 赋值
- 全天日程有 `!this.fAllDay` 判断
- `pickIsEnd = !isStart`(#34 主体防回归)
- 不再残留 `this.fEndDate < iso` 那种条件顺延
- 反向:改回老写法 / 只写日期不写时间 / 改结束顺手改开始 / `pickIsEnd` 再反过来
  → 逐条转红;**对照组**(只改一句注释)仍绿 —— 证明断言不会"见到改动就红"

> ⚠️ 接线判据自己第一版有 bug,是反向验证抓出来的:坏1 用正则
> `if \(!this\.fAllDay\) \{[\s\S]*?\n      \}` 找替换目标,但渲染层还有一个
> `if (!this.fAllDay)`(控制「结束」那一行显示),正则先吃到那个 ⇒ 注入落在无关位置
> ⇒ 断言仍绿(假阴性)。改成"先把 applyPicker 的函数体切出来再替换"。

**编译**:BUILD SUCCESSFUL,33 tasks(17 executed)。验签通过。

**⚠️ 已知存量失败(与本次无关)**:`_fb_arkts_guard.js` 跑出 1321 通过 / 3 失败,
三条都在工作区里**别的会话未提交的改动**上(`AGENDA_BACK_DAYS` 被换成 `CAL_FULL_FROM/TO`
导致"列表视图显式传日期范围"判据失配、`canEdit` 相关两条属 #31)。
本次只改 `FbDateTimeField.ets` 与 `FbEventEditSheet.ets`,不碰那些文件;
用 `git show HEAD:` 核实过 HEAD 版本里 `AGENDA_BACK_DAYS` 还在(判据本来通过)。
2026-11-01 09:38:14 +08:00
laoyang d2d0a435a3 日程编辑:点「开始」却改了结束时间 laoyang/FamilyBook#34
用户 2026-10-30:「鸿蒙端,日程添加时,选择时间,点上面,
修改的反而是结束时间,这个是 bug。」

根因:openPicker 的参数语义与调用方相反。
  · 调用方 dateTimeRow(label, isStart) 传的是 **isStart**
  · 被调用方签名却是 openPicker(isEnd),内部直接 pickIsEnd = isEnd
  ⇒ isStart=true(点开始)→ isEnd=true → 整条链路按"结束"处理。

错得很"自洽"所以一直没被发现:
  · 弹层初值读的是结束时间
  · 确认后写回的也是结束时间
  · 连标题都显示「选择结束时间」
三处一起错,"弹出来的值"和"改完的值"是一致的,看着不像坏。

修法:参数统一成 isStart(与调用方同名同义),内部自己取反。
  没在调用处写 openPicker(!isStart) —— 双重否定更容易再错一次。

对照:观影表单 FbMovieNewSheet 用同一个 FbDateTimePicker 组件,
但 pickIsEnd 是显式赋 false/true,没有正反颠倒的空间,不受影响。

验证:
  · 编译 BUILD SUCCESSFUL(33 tasks / 17 executed)
  · 从真实源码提取三条映射做断言:pickIsEnd=!isStart、
    读日期/读时间均在 isStart 时取 fStart* —— 全部通过
  · 真值表:点开始→读fStart*→写fStart*→标题「选择开始时间」,
    点结束→读fEnd*→写fEnd*→标题「选择结束时间」
  · 反向验证:拿修复前的代码跑同一判据,正确转红
    (旧版点开始时读写都是 fEnd*),证明判据不是恒真
  · 全仓库排查 isStart/isEnd 用法,无同类问题
2026-10-30 15:41:38 +08:00
laoyang 7bc26dd7e1 地点联想:改用鸿蒙自带 Map Kit,不再走高德 laoyang/FamilyBook#33
用户指示「端侧不用高德,用鸿蒙自带的接口」。

改用 @kit.MapKit 的 site.queryAutoComplete(),顺带解决原方案两个问题:
  ① 高德 Web 服务 key 是服务端密钥,本不该出现在客户端;
  ② 线上那个 key 实际是 JS API 类型、调 Web 服务接口一直失败(见 #33 排查记录)。
现在端上不需要任何外部 key,也不需要我们自己的服务端接口与配额。

改动:
- FbGeoRepo:site.queryAutoComplete({query}) -> sites[]
  取 name + formatAddress + location。
  formatAddress 的 SDK 注释原文是 "Formatted detailed address of a place",
  正是用户要的「作为参考的详细地址」。
  formatAddress 缺失时用 locality + streetName + streetNumber 兜底。
- FbAddrInput:去掉 token 参数(MapKit 鉴权走 AGC 应用认证,与 API 令牌无关)。
- FbEventEditSheet / FbTripNodeSheet:两处调用同步去掉 token。

错误码全部降级为空结果、不打扰用户(声明文件列明的):
  - 1002600003 App authentication failed
  - 1002600004 The Map permission is not enabled
  - 1002603001 Zero result(查不到,属正常业务结果,不刷错误日志)
  - 1002600002 Failed to connect to the Map Kit server
联想挂掉 => 退化成普通文本框,手敲照常保存。

字段名一律以声明文件 @hms.core.map.site.d.ts 为准:
StreetNumber 的字段是 streetName / streetNumber,
第一版凭印象写成 street / number,编译直接报
"Property 'street' does not exist on type 'StreetNumber'",已修正。

编译通过(33 tasks,17 executed)。
2026-10-30 08:12:15 +08:00
laoyang f4f27cea55 地点输入:补地址联想,下拉带详细地址好区分同名地点 laoyang/FamilyBook#36
用户 2026-10-30:「在所有调用高德显示详细地址的地方…不能只把地点告诉我,
一定要把详细地址也放在后面。因为同一个地址可能有好几个,
我根本不知道应该选哪一个。」

网页端(addr_suggest.js)已经是这个行为,端上原本**连联想都没有**(纯文本框)。
本次把能力补到端上:

- 新增 FbGeoRepo.ets:调服务端 /api/v1/geo/tips,最少 2 字才查
- 新增 FbAddrInput.ets:候选每行两行字(地名 14px 深色 + 详细地址 12px 灰),
  同名地点靠第二行区分;防抖 260ms(与网页端同节奏);用 seq 丢弃过期响应
- 日程编辑、行程节点两处地点接入

🔴 走服务端代理而不是端上直连高德:高德 Web 服务 key 是服务端密钥,
打进安装包等于公开(反编译/抓包即得,配额会被跑光、key 可能被封)。
网页端用的 JS API key + 安全密钥是域名白名单那套,原生端没有等价机制。

⚠️ 必须是 @ComponentV2 组件而不是 @Builder:@Builder 的值类型参数
不参与状态观察(SDK r/quick-rules/05-state.md),候选列表/展开态写在
@Builder 里会数据变了界面不重建。本项目在 FbEventChip/FbTagChip/
FbCalOptionRow 上各踩过一次。

⚠️ 联想失败一律返回空候选 ⇒ 退化成普通文本框,手敲照常保存
(接口挂/没网/没配 key 都不能拖垮主流程)。

编译通过(33 tasks,17 executed)。
2026-10-30 08:03:13 +08:00
laoyang 051d3974ba v86 首页补齐五项入口(就地编辑 + 4 张卡新建 + 新增观影/联系人卡)
用户 2026-10-24「端上也全部都实现」,即 v84 验收时留下的三条:
名册新增成员 / 首页日程弹框后的编辑 / 首页其他卡片的新增。

实现:
- 日程详情卡「编辑」改成就地叠编辑表单,不再 closeEvent()+switchModule
- 近期任务 / 最近纪念日 / 最近观影 / 联系人 四张卡加「+ 新建」
- 观影卡与联系人卡端上原来没有,本次新建(数据走本地仓储,/home 不返回)
- backOnce 按层加 6 个分支;@Monitor 覆盖 8 个标志位
- FbSectionTitle 扩 addText/onAdd(带默认值,老调用点不改)

真机验收抓出三个「断言全绿但用不了」的 bug,一并修掉:
1. 编辑表单所有按钮点不动 —— Stack 层叠顺序写反,详情卡的整屏遮罩
   盖在表单之上。dumpLayout 坐标全对、节点全在,只有真点才会发现。
2. 「+ 新建」点了没反应 —— syncNote 在本页只有赋值没有渲染点,
   失败分支静默 return。统一改成 note() = 赋值 + 当场 Toast。
3. 改选「不重复」存完还是「每天」—— recognize 的保护逻辑(防清掉自定义
   重复规则)误伤了「用户主动清空」:原规则非空 + 选 none ⇒ rrule 整项
   不发。加 fRepeatTouched 区分「归入 none」与「主动选 none」。

验证:守卫 1167/0 · 反向验证全量 242/0 · 装机成功
端到端落库 建→改→删 全走通,测试数据已清理
2026-10-24 20:22:35 +08:00
laoyang cdbf0a9593 v84: 首页「+ 新建」日程 + 红线去端点 + 新建表单两处可见性修复
用户 2026-10-23 原话:「日程,没有新建日程按钮,名册,也没有新增成员这个按钮。」
「首页上的日程,红色线不对,变短了左侧缺了一块。在日程模块中,那个红线左侧
是不是还有一个红点?如果有,去掉。」

① 首页日程区块加「+ 新建」(FbHomePage / Widgets.FbSectionTitle)
   - FbSectionTitle 扩两个可选参数 addText / onAdd,带默认值 ⇒ 老调用点一行不改
   - 按需懒拉 /calendar/books,缓存进 calBooks,同一会话只拉一次
   - todayIso() 用本地年月日拼,**不用 toISOString**(UTC 会让早 8 点前算成昨天)

② 时间红线两端统一成「一根满宽线、无端点装饰、无行首文字」(FbDayTimeline)
   - 老写法 `Row { Text(时间) width(34); 线; 圆点 }` ⇒ 行首 34vp 把线顶掉一块
     (与网页端 .ag-now「双重缩进」同一类病),行尾 6x6 圆点就是用户问的红点
   - 改成满高 Column + Blank 撑高 + 满宽 2px 线,与卡片端同一写法

③ 🔴 真机实测发现的两处可见性问题(FbEventEditSheet)
   - 「加入哪本日历」原来排在「提醒」之后 ⇒ 表单高于卡片(maxHeight 86%),
     它被推到滚动区下方,首屏只看到被底边切掉半行的标题(实测 bounds 高 7px)。
     它是必选项(没选就「请选一本日历」存不上)⇒ 挪到「全天」之后、日期时间之前。
   - 错误提示原来在滚动区**内部最底部** ⇒ 用户在顶部点「创建」时提示在几百 px
     之下看不见;就算滚到底也被 Scroll 底边切半行。现象是「点了创建什么都没发生」。
     ⇒ 挪到滚动区外面、按钮区上方(实测:Scroll 底 1953,提示 1984~2024,按钮 2074)。

真机验收(设备 5NC0225B27004718,线上 family.yangyq.net):
  - 静态守卫 1112/0;BUILD SUCCESSFUL;install bundle successfully
  - 「+ 新建」bounds [868,931][1018,1045],点击真的弹出「新建日程」
  - 诊断确认 books=15 canWrite=6(数据层完全正常,之前的「选不了日历本」是可见性问题)
  - 日历本挪位后首屏可见:标题高 40px(原 7px),10 本 chip 从 838 排到 1358
  - 错误提示挪位后不滚动即可见:命中「日程得有个标题」
  - **端到端建卡成功**:线上库确认 id=2411 cal=5 20:00~21:00,首页 1 条→2 条;
    测试数据已按 id 精确删除(remaining_test_rows=0),重启后恢复 1 条
2026-10-24 19:14:18 +08:00
laoyang 8146aab1a7 v63+v64:影院管理补齐(v63)与观影「记一场」豆瓣/弹框选择(v64)
⚠️ 本提交含**两批**改动(同一批文件里交织,无法按文件拆开):
  · v63(影院管理与搜索/统计/年报拆成平级入口)—— 本会话之外的工作,
    随本轮一并提交以免工作区长期留半成品;
  · v64(本会话,用户 2026-10-19 六条)。

v64 六条:
① 片名可经豆瓣自动获取简介与海报(与网页端同一份服务端输出:
   summary 全文 + 已落盘的 poster_key);简介**只填空白的**,不覆盖用户写过的。
   联想 320ms 防抖(与网页端同值)。
② 开始/结束改成**与日程同一个**日期时间选择控件 —— 新抽 components/FbDateTimeField.ets
   (行 + 弹层 + 一组换算函数),日程那边旧的自绘实现整段删掉改用它
   (用户要的就是"两处一样")。
③ 影院、同看人改成**弹框选择**:
   · FbCinemaPickSheet:顶部搜索框,匹配「地方 + 名称」,「不记录影院」恒在列表;
   · FbPersonPickSheet:顶部搜索框,拼音首字母**子序列**匹配(yyq 打成 yq 也能搜到),
     多选走"暂存 + 确定"两段式(点一个不关窗)。
   两排横向胶囊/头像全删(用户:"这种方式太难找了")。
④ 允许上传**多张**图片:海报 1 张 + 观影照片可一次选 9 张、可多次追加、可逐张删。
   ⚠️ 顺序是**先建记录再传图**(建记录失败就不会留孤儿图);图失败**不挡记录**。
⑤ 删掉「地点」输入口(location 字段仍发,网页端与历史数据不受影响)。
⑥ 观影页搜索框改明显:白底 + 实色描边 + 图标放大到 18 并染主题色 +
   占位文字提到 muted/fontBody + 右侧「筛选 ›」暗示(用户:"根本看不清")。

FbMovieRepo 新增 doubanSuggest / doubanFetch / uploadPoster / uploadPhoto
(multipart 手写,与头像上传同一形态,抽成共用的 uploadOne)。

验证:静态守卫 636/0 · 端上反向验证 87/0 · 接口 e2e 57/0 · 服务端反向验证 18/0 ·
本地全量 e2e 1521/0 · hvigor 编译成功并已装机。
⚠️ 真机验证脚本 _fb_v64_verify.py 已写好(六条全覆盖),因设备锁屏未能执行。
2026-10-20 07:35:37 +08:00
laoyang 853b0e0b20 v61:顶栏标题=模块名 / 抽屉瘦身 + 头像进个人设置 / 删除按钮红底 / 浮层动画 / 日程卡片与手势
用户这一批九条,逐条对应:

1)「页面上左上角的标题,不再是家书了,而是切换到那个模块,就显示哪个模块的标题。
   这样在页面内容部,就不再出现模块的名字标题了。」
   → TopBar 主标题改读 moduleName()(通知/设置/个人设置三个非模块路由也有名字);
     观影/纪念日/读书/笔记/通知五处页内大标题删掉。

2)「按钮,也需要和主题色保持一致,出现文字的时候,例如观影模块,
   在左上角出现的时候,颜色也需要和主题色保持一致。」
   → 标题色走 fbModuleColor(app.activeModule)(一处算,11 个页面不用各写)。

3)「弹框的外圈颜色,跟模块的主题色保持一致。」
   → 日程详情原来传 bookColor(日历本色)⇒ 改 accentColor();
     7 个模块设置浮层补传 accent: this.accent。

4)「删除按钮全部用红色背景。」
   → 日程编辑/人员编辑从红描边改红底白字;详情「删除联系人」从浅红底改红底白字;
     两处确认框统一 FbColors.red。

5)「做几个动画,例如,点击名册列表,应该有一个过渡动画出现弹框,
   点击详情,框变大了,也应该有一个过渡动画,点编辑,也有动画。」
   → 新建 common/FbAnim.ets(fbMaskTransition / fbSheetTransition /
     fbSheetGrowTransition / fbViewTransition),9 个页面共 17 遮罩 + 16 浮层挂上;
     简要卡→详情用 0.96→1 的"继续长大"(0.94 会先缩一下)。

6)「左侧抽屉,把通知消息、个人设置、修改密码、系统设置,都去掉,
   放在个人设置页,就是在点击右侧头像那里。消息通知不用放进去,
   直接在头像旁边那里就可以了。」
   → 抽屉底部那四行整块删除(抽屉只剩品牌区 + 模块列表);
     新建 pages/account/FbAccountPage.ets(整页,__account 分发),
     点头像 switchModule('__account');改密码真打服务端新接口。

7)「日程……日期下面:12本日历可见,本月124条,这句话去掉。
   点击日程弹出的框,编辑按钮也颜色也要修改。
   全天日程,例如农历,上面显示无标题,读不到这条日程,这个有问题。」
   → 删统计行;编辑按钮从写死名册青 #4A7C82 改模块主题色;
     真根因:衍生条目(农历/节气)的 detailFull **一直是 null**
     (它们没有 /events/<id> 可拉,原来直接 return)⇒ 垫 shellOf(),
     并把"整卡报错"改成"照常画内容 + 一行小字";
     空标题兜底从「(无标题)」改成日历本名。

8)「再做几个卡片,先做日程的,这个参考 synccalendar。」
   → FbDayEventPanel.eventRow 照 SyncCalendar:左侧 4vp 圆头色条 + 标题 +
     时间/全天 + 「↻ 重复」徽标 + 右端日历本名(限宽 30%、同色);
     一行一张独立圆角卡(12)+ 描边,卡间 space 8,不再用 Divider 连成一片。

9)「日程,有很多手势,你参考 synccalendar。」
   → 月历上滑→周视图、周条下划→月视图、周条左右滑→换周。
     真机实测两次踩空后定下写法:**竖向必须 parallelGesture(PanGesture)**
     (外层是 Scroll,SwipeGesture 的"快速划动"会被它的内置滚动先吃掉,
      gesture/priorityGesture 都不行);**横滑用 gesture(PanGesture)**
     (同一节点两条方向不同的 parallelGesture 会互相压制);
     方向按累计位移判、并要求 |dy| > |dx|。切视图走 animateTo + fbViewTransition。

验证:
· 编译 BUILD SUCCESSFUL
· ArkTS 守卫 493/0;Schema 列守卫 12/0;反向验证 39/0(新增 22 条注入逐条确认能变红)
· 服务端接口 e2e 20/0(独立副本 + 真 MariaDB,5 种错误路径 + 原令牌仍有效)
· 真机 _fb_v61_verify.py 21/0(6 组全过);像素采样确认浮层主题色环实测存在
2026-10-19 12:19:54 +08:00
laoyang 1a67247407 v60b:所有弹框统一主题色描边环 + 编辑改居中弹框 + 修名册下拉回弹吃掉悬浮栏
1)9 个浮层统一描边环(抽组件,不复制 8 遍)
   新增 components/FbSheetRing.ets:环宽 FB_RING_W=2 全工程唯一一处;
   实现是"外层 Column 铺色 + padding",不是 border(border 画在盒子内侧);
   外圆角 = 内圆角 + 环宽。简要卡/详情/编辑/日程详情/日程编辑/观影详情/影院/
   日程设置/模块设置全部改用;各浮层的环色 = 所属模块的主题色。

2)编辑从"贴底满宽 + 只有上圆角"改成居中弹框
   人员编辑与日程编辑:Stack 对齐改 Center,卡片 92% 宽 + 四角圆 + 环;
   constraintSize 留在卡片自己身上(挪到外层会让内层 Scroll().layoutWeight
   拿到 0 高度,资料区塌成一条线)。日程的日期时间选择弹层、两个删除确认框
   一并套环,避免同一次交互里出现两种形态。

3)修名册下拉到头回弹后悬浮按钮消失
   EdgeEffect.Spring 在越界松手后把内容弹回,每帧 offset>0 被当成"用户在往上滑"
   ⇒ 收起悬浮栏。判据 = 手指已抬起 + 最后一次方向是下滑 + 抬手不到 500ms;
   拦截必须排在 offset >= HIDE_AT 快路径之前(回弹第一帧位移常 >= 12vp)。

4)真机截图暴露的两个观感问题(静态检查全绿也照错)
   - Scroll().layoutWeight(1) 让短内容也撑满 maxHeight ⇒ 卡片空半屏
     (日程详情/模块设置),改为 flexShrink(1);内容本来就长的浮层不动。
   - 人员编辑"虚拟人物(还没弄清真实身份)"被卡片裁掉半句:两个小开关从
     并排 Row 改为 Flex(wrap) 换行,间距改走 margin。

验证:ArkTS 守卫 444/0;反向验证 17/17;真机 _fb_v60b_verify.py 11/0,
且关掉回弹拦截重编重装后该用例确实变红(证明测试不是假绿);
9 个浮层逐个真机截图确认。
2026-10-19 08:29:44 +08:00
laoyang 7858de27e3 v0.8.4 简要卡观感 / 分享 / 名册搜索 / 全局返回手势(v59e)
八条需求的落地与真因:

1. 浮层与白底"糊在一起"、看不清 —— 根因不是配色,是**遮罩从来没画出来过**:
   ArkUI 的八位色值是 #AARRGGBB(alpha 在前),而全应用写的是 '#00000066'
   (本意"黑 40%")⇒ alpha = 0x00 ⇒ 全透明。同型还有 brand + '1A'(拼到了蓝通道)
   与 shadow('#00000033')。⇒ 17 个文件统一改走 fbAlpha() / FB_MASK / FB_SHADOW /
   FB_HAIRLINE;真机像素采样复验:遮罩 (148,146,140)、卡片白、浅底 (237,242,243)。
2. 简要卡外圈加**主题色描边环**(外层铺色 + padding,不是 border —— border 会被
   内层圆角切出白缝)。
3. 简要卡**去掉删除按钮**,删除挪到完整详情卡最下面(Divider + 红字块)。
   顺手修一处静默失败:confirmDelete() 原来只取 quickSource(),
   从家谱直接开详情时 quickPerson 为 null ⇒ 点删除毫无反应。
4. 信息行间距 10 → 16(每行再各加 3vp 上下内边距,实测行距 134/118px)。
5. 主电话整行可点**直接拨号**(call.makeCall,落到系统拨号盘)。
6. 按钮改为 详情 / 编辑 / 分享 / 关闭;分享走系统分享面板,
   内容为纯文本「姓名 / 电话 / 邮箱」三项(用户点名的就是这三项,
   不多带单位),面板拉不起来时兜底复制到剪贴板并提示。
7. 名册搜索"完全不能用"有两个独立真因:
   ① 搜索框是 List 的第一个 item,无结果时整个 List 被空态替换 ⇒ 输入框被卸载、
      焦点丢失 ⇒ 输不进第二个字。改:List 无条件渲染,空态自身做成 ListItem。
   ② rowToPerson 把 initials 写死成空串,服务端下发的拼音首字母从未落库 ⇒
      拼音搜索恒 0 结果。改:FB_DB_VERSION 6→7 + PRAGMA 探测补列 + 同步时落库;
      匹配同时遍历全部电话(原来只比主号)。
   另加搜索框「清空」(24×24 命中区)。
8. 全局返回手势:应用是单页 + 模块分发、没有路由栈 ⇒ 自建 FB_BACK 登记表
   (倒序询问)+ moduleHistory + applyModule()(不记历史,否则 A/B 两页来回弹)。
   9 个页面登记/注销;Index.onBackPress 先关浮层 → 回上一模块 → 才 return false
   交给系统退桌面(onBackPress 必须声明 boolean,返回 void 会被当成没接管)。

验证:
- 静态守卫 417 / 0(新增 ⑤阴影·描边·色环 ⑥透明度色 ⑦返回手势 ⑧搜索 ⑨分享)
- 反向验证 10 / 0(9 条注入全部能让守卫变红;其中"遮罩换纯黑"那条暴露了
  一条存在型假绿,已改成数个数 + 禁止 Color.Black)
- 建表/迁移列一致性守卫 12 / 0
- 真机全模块遍历 14 / 14;真机逐项复核 12 / 0 与 7 / 0

工具侧顺带修好两个过期的探针:
- 遍历探针仍用"应用内横滑"打开抽屉,而该手势早已按用户要求去掉、入口改为顶栏图标
  ⇒ 一次全量遍历里 12 个模块全报"抽屉里没找到"(像应用坏了,其实是探针过期)。
- 资源/笔记两页写死了早已不存在的条目(户口本/房产证/阳台改造清单)⇒ 改成
  结构性文案(副标题 + 常驻筛选胶囊),不随用户数据变化而恒红。
2026-10-18 23:12:57 +08:00
laoyang 776c95ba0b v0.7.0 接上真实服务器:登录 / 设备会话 / 全量同步与各模块真实数据
从「演示数据壳子」走到「真的能连家里的服务器用」。

登录(用户 2026-10-17「完整的登录功能」)
  · 首次启动先填服务器地址 → /api/v1/ping 自报门户(认得出"这地址上真是家书")
  · 手机号或用户名 + 密码 → 拿令牌;失败提示统一,不泄露账号是否存在
  · FbDeviceStore:首次启动生成并持久化设备 UUID(三方应用拿不到 UDID),
    设备名取机型(marketName),并上报 platform / app_version

设备会话(v57,用户 2026-10-17)
  · 一把令牌 = 一台设备的一条会话;每次启动打一次 /me(有网就验)
  · 两种锁分开:need_login(401/被踢 → 清令牌)与 offline_expired
    (离线超 24h → 只锁界面、不清数据、联网自动恢复)——
    混成一种就会违背用户要的"一直联网就不用每天输密码"
  · 运行期任何请求 401 → 网络层全局回调立刻锁定跳登录页(FbHttp 的 authProbe
    让登录/校验类请求跳过,避免"两个地方同时跳登录页")
  · 退出登录:先清本地令牌(主防线),再尽力通知服务端
  · 设置页显示版本号与「这台设备」

数据层
  · FbDb / FbSchema / FbParse / 各 Repo(日程 / 名册 / 观影 / 模块)+ FbSyncAll
  · 首页改为服务端 /home(农历/节气/纪念日/生日/天气/统计/往年的今天)
  · 日程页用 FbDayEventPanel,与网页端显示方式/红线/并排三处一致

验证:ArkTS 静态守卫 231/0;hvigor 编译 BUILD SUCCESSFUL(entry-default-signed.hap)。
2026-10-18 03:36:04 +08:00