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)。
This commit is contained in:
2026-10-18 03:36:04 +08:00
parent 7eaa641437
commit 776c95ba0b
64 changed files with 18297 additions and 1519 deletions
@@ -0,0 +1,50 @@
/**
* 家书 FamilyBook · 可选中胶囊片(鸿蒙端)
*
* 日程「新建/编辑」里给**重复**和**提醒**两组选项用。
*
* 🔴🔴 为什么必须是**组件**而不是 `@Builder`(用户 2026-10-16 报的真 bug):
* 「重复和提醒都挤在一块了……而且**重复和提醒什么的都点不了**。」
* 根因:原来是 `FbEventEditSheet.chip(label, on: boolean, onTap)` ——
* **`@Builder` 的值类型参数(boolean)不参与状态观察**
* (SDK 规则 `r/quick-rules/05-state.md`:按值传递「状态变化刷新 ❌」)。
* ⇒ 点一下 `this.fRepeat` / `this.fRemind` 确实改了、保存也发得出去,
* 但**选中态那份子树不重建** ⇒ 界面上没有任何反馈 ⇒ 看着"点不了"。
* 本项目已在 `FbTagChip`、`FbCalOptionRow` 上踩过同一个坑(各见其文件头)。
* ⇒ 统一做法:抽成 `@ComponentV2` + `@Param active`。
*
* ⚠️ 顺带的另一处:它原来是裸放在 `Flex({wrap})` 里、**没有 margin** ——
* 项目里别处的 wrap 都写了 `.margin({ right: 8, bottom: 8 })`
* (见 `FbHomePage` 的标签云、`FbSettingsPage` 的色板)。
* 少了 margin,两行 chip 会**贴在一起**(这正是"挤在一块"的观感来源)。
* ⇒ margin 放在**本组件根节点**上,调用方不用再写。
*/
import { FbColors, FbMetric } from '../common/Theme';
@ComponentV2
export struct FbEventChip {
/** 显示文字 */
@Param label: string = '';
/** 是否选中(**必须由父组件按状态算好传进来**) */
@Param active: boolean = false;
/** 选中时的底色(默认用日程模块的主题色;日历本那组传本色) */
@Param activeBg: string = '#4A7C82';
/** 被点击 */
@Event onPick: () => void = (): void => {
};
build() {
Text(this.label)
.fontSize(FbMetric.fontSmall)
.fontColor(this.active ? Color.White : FbColors.muted)
.backgroundColor(this.active ? this.activeBg : FbColors.inputBg)
.borderRadius(FbMetric.radiusPill)
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
// ⚠️ 间距放在组件内部:wrap 容器里的子项必须自己有 margin,否则会贴在一起
.margin({ right: 8, bottom: 8 })
.onClick((): void => {
this.onPick();
})
}
}