首页联系人:点编辑就地弹框,不再跳名册 (#90)
用户:现在在首页上,弹出名册信息之后,点击编辑,怎么跳转到名册去了?
点击编辑应该直接弹框编辑。
改前 onEdit = closePersonDetail() + switchModule(people) —— 用户被甩到
名册模块,还得自己重新找到那个人再点编辑,绕了一圈。
当时注释的理由"首页没有人员编辑表单"站不住:首页**已经**在用
FbPersonEditSheet 做新增成员,同一个组件换参数就是编辑模式。
① onEdit 改为就地弹表单(同一个 FbPersonEditSheet,不另写一份,
否则两处字段/校验/保存逻辑必分叉);
② 新增 @Local pfEditing: FbRosterPerson | null —— 用对象不用 boolean
(表单要拿它回填,只存 true/false 还得再查一次库)。
与 pfCreating 分开两个状态:新建时 person = null 是合法值,
合并成一个 boolean + person? 会让两种情形撞车;
③ 取消 ⇒ 回详情卡(不是直接回首页)。用户刚才是从详情进来的,
取消只是"我不改了",不该连"我在看谁"一起丢掉(与名册页同口径);
④ 保存 ⇒ 关表单 + reloadSideCards + refreshPersonDetail(id)。
这里有个必须处理的坑:编辑表单 save() **只调接口、不写回本地库**,
直接把编辑前快照塞回 pfDetail 会让用户看到"改完还是旧名字"。
⇒ 新增 refreshPersonDetail(),两级刷新(与 FbPeoplePage.openDetail 同一思路):
① byId() 读本地库(快,可能是旧值)
② fetchDetail() 打 GET /people/<id>(服务端权威值,回来原地替换)
断网保持①、不弹错;读不到就什么都不做,不拿 null 覆盖正常的详情卡。
验证(真机 5NC0225B27004718):
- 首页点爸爸→详情卡→点编辑 → **就地弹出编辑表单**,页面仍是首页
(下方最近观影/联系人/往年的今天都在);
- 表单标题「编辑资料」、姓名回填「杨培振」、生日(阳历)1955-03-30;
- 点取消 → 回到详情卡(含手机号/拨打/编辑),不是直接回首页。
hvigorw assembleHap BUILD SUCCESSFUL。
⚠️ 刻意没执行"保存":这是用户真实联系人数据;保存路径与名册页完全
同一份代码(同组件同 onSaved),无需在首页重复踩。refreshPersonDetail
的两级刷新未走真机保存验证 —— 若日后发现"保存后详情显示旧值"先查这里。
This commit is contained in:
@@ -363,6 +363,21 @@ export struct FbHomePage {
|
||||
|
||||
/** 「新增成员」表单开着 */
|
||||
@Local pfCreating: boolean = false;
|
||||
/**
|
||||
* 正在**编辑**的那个人(null = 编辑浮层没开)。
|
||||
*
|
||||
* 🔴 用户 2026-11-06:「现在在首页上,弹出名册信息之后,点击编辑,
|
||||
* 怎么跳转到名册去了?点击编辑应该直接弹框编辑。」
|
||||
* ⇒ 原来 `onEdit` 是"关掉详情卡 + `switchModule('people')`",
|
||||
* 用户被整个甩到另一个模块,还得自己再找一遍那个人 —— 很难用。
|
||||
* 现在改成就地打开同一张表单(与名册页同一个组件 `FbPersonEditSheet`)。
|
||||
*
|
||||
* ⚠️ 用**对象**而不是 `boolean`:编辑表单要拿它回填(姓名/电话/生日/工作经历…),
|
||||
* 只存 true/false 还得再去库里查一次。
|
||||
* ⚠️ 与 `pfCreating` 分开两个状态,不要合并成一个 `boolean + person?`:
|
||||
* 新建时 `person = null` 是合法值(不是"没开"),合并后这两种情形会撞车。
|
||||
*/
|
||||
@Local pfEditing: FbRosterPerson | null = null;
|
||||
/** 联系人卡要显示的人(本地库前 N 个) */
|
||||
@Local pfRecent: FbRosterPerson[] = [];
|
||||
/** 名册总人数(卡片底部"共 N 人"用) */
|
||||
@@ -737,6 +752,48 @@ export struct FbHomePage {
|
||||
this.pfDetail = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 id 重读一个人,并(若该人正是当前详情卡)把详情卡换成最新值。
|
||||
*
|
||||
* 🔴 2026-11-06:首页支持就地编辑后必须补这一步。
|
||||
* 编辑表单 `FbPersonEditSheet.save()` **只调接口、不写回本地库**
|
||||
* (见那里的实现:PATCH 完直接 `onSaved()`)。所以:
|
||||
* 把编辑前那份快照塞回 `pfDetail` 会让用户看到"改完还是旧名字"。
|
||||
*
|
||||
* ⇒ **两级刷新**,与名册页 `FbPeoplePage.openDetail()` 同一思路:
|
||||
* ① `byId()` 先读本地库 —— 快,但可能是旧值(编辑不一定同步了库);
|
||||
* ② `fetchDetail()` 再打 `GET /people/<id>` —— 服务端权威值,
|
||||
* 回来就原地替换。断网时保持 ① 的显示,不弹错误。
|
||||
*
|
||||
* ⚠️ 读不到(那人被删了、或令牌为空)就**什么都不做**,
|
||||
* 不要拿 null 去覆盖一个正常打开的详情卡。
|
||||
* ⚠️ 用 `pfDetailId` 防"改 A 期间又去改 B"——响应回来时若详情卡
|
||||
* 已经换成别人,这次结果就该丢弃(名册页用 detailToken 干这件事)。
|
||||
*/
|
||||
private async refreshPersonDetail(id: number): Promise<void> {
|
||||
if (id <= 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
/* ① 本地库(快) */
|
||||
const local: FbRosterPerson | null = await FbPersonRepo.inst().byId(id);
|
||||
if (local !== null && this.pfDetail !== null && this.pfDetail.id === id) {
|
||||
this.pfDetail = local;
|
||||
}
|
||||
/* ② 服务端权威值(准) */
|
||||
const token: string = FB_TOKEN_STORE.get();
|
||||
if (token === '') {
|
||||
return;
|
||||
}
|
||||
const full: FbRosterPerson | null = await FbPersonRepo.inst().fetchDetail(id, token);
|
||||
if (full !== null && this.pfDetail !== null && this.pfDetail.id === id) {
|
||||
this.pfDetail = full;
|
||||
}
|
||||
} catch (err) {
|
||||
hilog.warn(DOMAIN, TAG, '重读联系人失败(id=%{public}d):%{public}s', id, JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拨号(点联系人详情里的手机号时)。
|
||||
*
|
||||
@@ -2321,10 +2378,15 @@ export struct FbHomePage {
|
||||
this.closePersonDetail();
|
||||
},
|
||||
onEdit: (): void => {
|
||||
/* 关掉详情卡,跳到名册去改 —— 首页没有人员编辑表单,
|
||||
与其在这里硬塞一份,不如交给名册(那是它的主场)。 */
|
||||
/* 🔴 用户 2026-11-06:「点击编辑应该直接弹框编辑。」
|
||||
改前这里是「关掉详情卡 + `switchModule('people')`」——
|
||||
把用户整个甩到名册模块,他还得自己再找一遍那个人。
|
||||
⇒ 现在就地打开同一张表单(`FbPersonEditSheet`,与名册页同一个组件)。
|
||||
⚠️ 先把详情卡收起来:两层浮层叠着会互相抢点击,
|
||||
而且用户改完最想看到的是"改对了没"(见 `onSaved`)。 */
|
||||
const who: FbRosterPerson | null = this.pfDetail;
|
||||
this.closePersonDetail();
|
||||
this.app.switchModule('people');
|
||||
this.pfEditing = who;
|
||||
},
|
||||
/* 🔴 用户 2026-11-06:「点开以后的弹窗,点击手机号可以直接拨打电话。」
|
||||
⚠️ 卡片只发号码,真正拨号走本页 `dial()`(理由见那里的注释)。 */
|
||||
@@ -2482,6 +2544,66 @@ export struct FbHomePage {
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
|
||||
// ==================== 联系人**编辑**(#89 后续)====================
|
||||
/* 🔴 用户 2026-11-06:「现在在首页上,弹出名册信息之后,点击编辑,
|
||||
怎么跳转到名册去了?点击编辑应该直接弹框编辑。」
|
||||
|
||||
改前 `onEdit` 是 `switchModule('people')` —— 把用户甩到名册模块。
|
||||
现在就地弹表单,用**同一个组件** `FbPersonEditSheet`(与名册页一致):
|
||||
不另写一份,否则两处字段/校验/保存逻辑必然分叉。
|
||||
|
||||
⚠️ 遮罩 + 卡片成对写(本项目所有浮层的约定):
|
||||
遮罩在前、卡片在后,点遮罩等于取消。
|
||||
⚠️ `isCreate` 不传(默认 false)⇒ 编辑模式,表单会用 `person` 回填。 */
|
||||
if (this.pfEditing !== null) {
|
||||
Column()
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor(FB_MASK)
|
||||
.transition(fbMaskTransition())
|
||||
.onClick((): void => {
|
||||
this.pfEditing = null;
|
||||
})
|
||||
|
||||
FbPersonEditSheet({
|
||||
person: this.pfEditing,
|
||||
/* 已有标签供点选(与新建同一个来源;不传的话用户只能手打,
|
||||
很容易出现"同事"和"同 事"两个标签) */
|
||||
knownTags: this.personKnownTags(),
|
||||
accent: this.peopleAccent(),
|
||||
onCancel: (): void => {
|
||||
/* 🔴 取消 ⇒ **回到详情卡**(不是直接回首页)。
|
||||
用户刚才是从详情进来的,取消只是"我不改了",
|
||||
不该连"我在看谁"一起丢掉 —— 与名册页 `onCancel` 同口径。 */
|
||||
const who: FbRosterPerson | null = this.pfEditing;
|
||||
this.pfEditing = null;
|
||||
this.pfDetail = who;
|
||||
},
|
||||
onSaved: (): void => {
|
||||
/* 保存成功 ⇒ 关表单、重读卡片数据,并把详情卡重新打开。
|
||||
⚠️ 重新打开用的是**编辑前那份快照**(`pfEditing`),
|
||||
它可能是旧值(比如刚改了昵称)。所以紧接着要按 id
|
||||
从本地库重读一次,拿服务端权威值盖掉 —— 否则用户会看到
|
||||
"改完还是旧名字"(服务端已入库,界面却是旧的)。 */
|
||||
const who: FbRosterPerson | null = this.pfEditing;
|
||||
this.pfEditing = null;
|
||||
this.reloadSideCards();
|
||||
if (who !== null) {
|
||||
/* ⚠️ 不能 await:`onSaved` 是同步回调(`() => void`)。
|
||||
用 `.catch()` 显式兜住,别让一个失败的读库变成未捕获的 Promise 拒绝。 */
|
||||
this.refreshPersonDetail(who.id).catch((): void => {
|
||||
});
|
||||
}
|
||||
},
|
||||
onDeleted: (): void => {
|
||||
/* 首页这张卡**不给删**(`canDelete: false`,避免误删),
|
||||
走不到这里;置 null 只是兜底,别留一个打不开的浮层。 */
|
||||
this.pfEditing = null;
|
||||
}
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
|
||||
Reference in New Issue
Block a user