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:
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 家书 FamilyBook · 模块设置浮层(鸿蒙端)
|
||||
*
|
||||
* 🔴 用户 2026-10-16:「**所有页面的设置按钮全部都改成和网页版一致**,
|
||||
* 就是**三个横线**那种设置按钮。」
|
||||
*
|
||||
* 网页版的做法(`templates/` 下各模块的 `_settings_menu.php`):
|
||||
* 每个模块的动作区最右有一个 `<details class="movie-set menu">`,
|
||||
* `summary` 里就是**三条横线**的 SVG
|
||||
* (`M2.5 4.5h11M2.5 8h11M2.5 11.5h11`),点开是一个菜单列表,
|
||||
* 每条**图标 + 文字**。
|
||||
*
|
||||
* 🔴 本组件就是那个"点开后的菜单"(鸿蒙端做成底部浮层,与家书其它浮层同一形态)。
|
||||
* ⚠️ **通用**:各模块只是条目不同,所以做成一个组件 + 传 `items`,
|
||||
* 而不是给 8 个模块各写一个浮层(那种写法必然漂移)。
|
||||
*
|
||||
* ⚠️ 条目点了"还没做"的怎么办:**照实显示为不可用**(灰掉 + "暂未开放"),
|
||||
* 而不是让点击没反应 —— 后者用户会以为卡了。
|
||||
*/
|
||||
|
||||
import { FbColors, FbMetric, FbIcon } from '../common/Theme';
|
||||
|
||||
/** 贴底卡片的手势区缓冲(vp)—— 同其它浮层 */
|
||||
const FB_SHEET_BOTTOM_GAP: number = 16;
|
||||
|
||||
/** 设置菜单里的一条 */
|
||||
export interface FbSettingItem {
|
||||
/** 图标名(`FbIcon.ui()` 的 key,如 'chart' / 'gear' / 'filter') */
|
||||
icon: string;
|
||||
/** 文字 */
|
||||
label: string;
|
||||
/** 一句话说明(可为空) */
|
||||
hint: string;
|
||||
/**
|
||||
* 点了做什么。传空串 = **这项还没做**(画成灰色 + "暂未开放",点了不响应)。
|
||||
* ⚠️ 用 string 而不是回调:@Param 传函数在 ArkTS 里会被"不可序列化"折腾,
|
||||
* 这里只需要一个"标识",由父组件的 @Event 统一分发。
|
||||
*/
|
||||
action: string;
|
||||
}
|
||||
|
||||
@ComponentV2
|
||||
export struct FbModuleSettingsSheet {
|
||||
/** 标题(如「观影设置」) */
|
||||
@Param title: string = '设置';
|
||||
/** 菜单条目 */
|
||||
@Param items: FbSettingItem[] = [];
|
||||
/** 关闭 */
|
||||
@Event onClose: () => void = (): void => {
|
||||
};
|
||||
/** 点了某条(`action` 是条目的标识) */
|
||||
@Event onPick: (action: string) => void = (a: string): void => {
|
||||
};
|
||||
|
||||
build() {
|
||||
Column({ space: 0 }) {
|
||||
// ---- 标题栏 ----
|
||||
Row() {
|
||||
Text(this.title)
|
||||
.fontSize(FbMetric.fontTitle)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.fontColor(FbColors.ink)
|
||||
.layoutWeight(1)
|
||||
Text('完成')
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor('#4A7C82')
|
||||
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
|
||||
.onClick((): void => {
|
||||
this.onClose();
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
Scroll() {
|
||||
Column({ space: 0 }) {
|
||||
ForEach(this.items, (it: FbSettingItem) => {
|
||||
this.settingRow(it)
|
||||
}, (it: FbSettingItem): string => 'st_' + it.action + '_' + it.label)
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ top: 10 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.width('100%')
|
||||
.scrollBar(BarState.Off)
|
||||
.align(Alignment.TopStart)
|
||||
}
|
||||
.width('100%')
|
||||
.constraintSize({ maxHeight: '70%' })
|
||||
.padding({ left: 18, right: 18, top: 18, bottom: 20 + FB_SHEET_BOTTOM_GAP })
|
||||
.backgroundColor(FbColors.surface)
|
||||
.borderRadius({ topLeft: FbMetric.radius, topRight: FbMetric.radius })
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
|
||||
/**
|
||||
* 一条菜单项:**图标 + 文字**(照网页版:`每条文字前都要有图标`)。
|
||||
*
|
||||
* ⚠️ 未实现的条目(`action === ''`)画灰、且**不响应点击** ——
|
||||
* "点了没反应"比"明确告诉你还没做"更糟(用户会以为卡死)。
|
||||
*/
|
||||
@Builder
|
||||
settingRow(it: FbSettingItem) {
|
||||
Row({ space: 12 }) {
|
||||
Image(FbIcon.ui(it.icon))
|
||||
.width(17)
|
||||
.height(17)
|
||||
.renderMode(ImageRenderMode.Template)
|
||||
.fillColor(it.action === '' ? FbColors.faint : FbColors.muted)
|
||||
Column({ space: 1 }) {
|
||||
Text(it.label)
|
||||
.fontSize(FbMetric.fontBody)
|
||||
.fontColor(it.action === '' ? FbColors.faint : FbColors.ink)
|
||||
if (it.hint !== '') {
|
||||
Text(it.hint)
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.faint)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
}
|
||||
}
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.layoutWeight(1)
|
||||
|
||||
if (it.action === '') {
|
||||
Text('暂未开放')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.faint)
|
||||
} else {
|
||||
Text('›')
|
||||
.fontSize(FbMetric.fontBody)
|
||||
.fontColor(FbColors.faint)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ left: 12, right: 12, top: 12, bottom: 12 })
|
||||
.borderRadius(FbMetric.radiusS)
|
||||
.margin({ bottom: 6 })
|
||||
.backgroundColor(it.action === '' ? Color.Transparent : FbColors.inputBg)
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.onClick((): void => {
|
||||
// ⚠️ 未实现的项**点了不响应**(不是"关闭浮层")——
|
||||
// 否则用户以为"点了进去但没东西"
|
||||
if (it.action !== '') {
|
||||
this.onPick(it.action);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user