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 · 装机成功
端到端落库 建→改→删 全走通,测试数据已清理
This commit is contained in:
2026-10-24 20:22:35 +08:00
parent cdbf0a9593
commit 051d3974ba
2 changed files with 865 additions and 42 deletions
@@ -162,6 +162,17 @@ export struct FbEventEditSheet {
@Local fNote: string = '';
/** 重复的 key(REPEAT_OPTS 里那个) */
@Local fRepeat: string = 'none';
/**
* 🔴 用户**是否亲手点过**重复选项(v86d)。
*
* 为什么要这一位:`save()` 里有个保护逻辑 —— 原日程的 `rrule` 若非空
* 而端上认不出(归到 `none`),就不发 `rrule`,免得把人家自定义的规则清掉。
* 但这条保护**误伤了一个常见操作**:原规则是「每天」,用户改选「不重复」,
* 此时 `fRepeat === 'none'` 且 `event.rrule !== ''` ⇒ 被判成"认不出"⇒
* **整项跳过、规则原样保留** ⇒ 用户看着选了不重复,存完还是每天,且毫无提示。
* ⇒ 用这一位区分"归入 none"(初始态/认不出)与"主动选了 none"(要清空)。
*/
@Local fRepeatTouched: boolean = false;
/** 提醒分钟(可多选;空数组 = 不提醒) */
@Local fRemind: number[] = [];
/** 选中的日历本 id */
@@ -479,6 +490,11 @@ export struct FbEventEditSheet {
active: this.fRepeat === o.key,
onPick: (): void => {
this.fRepeat = o.key;
/* 🔴 v86d(2026-10-24 真机事故):**记下"用户真的点过"**。
详见 `save()` 里 `recognize` 的说明 —— 没有这一位,
用户从「每天」改选「不重复」时,保存会把这项**整条跳过**,
于是"选了不重复、存完还是每天",而且**没有任何报错**。 */
this.fRepeatTouched = true;
}
})
}, (o: FbRepeatOpt): string => 'rp_' + o.key)
@@ -821,11 +837,17 @@ export struct FbEventEditSheet {
note: this.fNote,
reminder_minutes: this.fRemind
};
// ⚠️ 重复:只在用户**确实选过**时才发。
// 编辑一条"自定义重复"的日程时,端上认不出来(归到"不重复"),
// 若照样发个空 rrule,就会把人家原来的规则**清掉**。
// ⇒ 规则原文认不出(非空且 chip 是 none)⇒ 这一项**不发**,保持原样。
const recognize: boolean = this.fRepeat !== 'none'
/* ⚠️ 重复:只在**能确定用户意图**时才发。
两种情况会走到这里:
① 用户**亲手点过**某个 chip(含"不重复")⇒ 以他点的为准,必须发。
② 用户没点过,但原日程的 `rrule` 本来就认得出(或本来就是空)⇒ 发原值。
留空的唯一情形:用户没点过、且原规则非空又认不出(自定义重复)——
这时发空 `rrule` 会把人家的规则**清掉**,所以宁可不发。
🔴 v86d 修的正是漏掉情况 ① 里的"主动选不重复":
原写法只判 `fRepeat !== 'none'`,于是"每天 → 不重复"被判成认不出,
整项跳过 ⇒ 存完还是每天(真机实测,用户会以为点了没生效)。 */
const recognize: boolean = this.fRepeatTouched
|| this.fRepeat !== 'none'
|| (this.event !== null && this.event.rrule === '');
if (recognize) {
input.rrule = this.ruleOfRepeat();
File diff suppressed because it is too large Load Diff